Merge tag 'drm-intel-next-2014-11-21-fixed' of git://anongit.freedesktop.org/drm...
authorDave Airlie <airlied@redhat.com>
Tue, 2 Dec 2014 22:25:59 +0000 (08:25 +1000)
committerDave Airlie <airlied@redhat.com>
Tue, 2 Dec 2014 22:25:59 +0000 (08:25 +1000)
drm-intel-next-2014-11-21:
- infoframe tracking (for fastboot) from Jesse
- start of the dri1/ums support removal
- vlv forcewake timeout fixes (Imre)
- bunch of patches to polish the rps code (Imre) and improve it on bdw (Tom
  O'Rourke)
- on-demand pinning for execlist contexts
- vlv/chv backlight improvements (Ville)
- gen8+ render ctx w/a work from various people
- skl edp programming (Satheeshakrishna et al.)
- psr docbook (Rodrigo)
- piles of little fixes and improvements all over, as usual

* tag 'drm-intel-next-2014-11-21-fixed' of git://anongit.freedesktop.org/drm-intel: (117 commits)
  drm/i915: Don't pin LRC in GGTT when dumping in debugfs
  drm/i915: Update DRIVER_DATE to 20141121
  drm/i915/g4x: fix g4x infoframe readout
  drm/i915: Only call mod_timer() if not already pending
  drm/i915: Don't rely upon encoder->type for infoframe hw state readout
  drm/i915: remove the IRQs enabled WARN from intel_disable_gt_powersave
  drm/i915: Use ggtt error obj capture helper for gen8 semaphores
  drm/i915: vlv: increase timeout when setting idle GPU freq
  drm/i915: vlv: fix cdclk setting during modeset while suspended
  drm/i915: Dump hdmi pipe_config state
  drm/i915: Gen9 shadowed registers
  drm/i915/skl: Gen9 multi-engine forcewake
  drm/i915: Read power well status before other registers for drpc info
  drm/i915: Pin tiled objects for L-shaped configs
  drm/i915: Update ring freq for full gpu freq range
  drm/i915: change initial rps frequency for gen8
  drm/i915: Keep min freq above floor on HSW/BDW
  drm/i915: Use efficient frequency for HSW/BDW
  drm/i915: Can i915_gem_init_ioctl
  drm/i915: Sanitize ->lastclose
  ...

815 files changed:
CREDITS
Documentation/DocBook/drm.tmpl
Documentation/devicetree/bindings/drm/imx/fsl-imx-drm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/drm/imx/hdmi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/drm/imx/ldb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
Documentation/devicetree/bindings/panel/auo,b116xw03.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/hannstar,hsd070pww1.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/hit,tx23d38vm0caa.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/innolux,g121i1-l01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/sharp,lq101r1sx01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pci/pci.txt
Documentation/devicetree/bindings/pinctrl/img,tz1090-pdc-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/lantiq,falcon-pinumx.txt
Documentation/devicetree/bindings/pinctrl/lantiq,xway-pinumx.txt
Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-sirf.txt
Documentation/devicetree/bindings/pinctrl/pinctrl_spear.txt
Documentation/devicetree/bindings/pinctrl/qcom,apq8064-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,apq8084-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,ipq8064-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,msm8960-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt
Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt [deleted file]
Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt [deleted file]
Documentation/devicetree/bindings/staging/imx-drm/ldb.txt [deleted file]
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/devicetree/bindings/video/adi,adv7511.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/exynos_dsim.txt
Documentation/devicetree/bindings/video/samsung-fimd.txt
Documentation/filesystems/overlayfs.txt
Documentation/networking/timestamping.txt
MAINTAINERS
Makefile
arch/arm/boot/dts/exynos5250-snow.dts
arch/arm/boot/dts/exynos5250.dtsi
arch/arm/boot/dts/r8a7740.dtsi
arch/arm/boot/dts/r8a7779-marzen.dts
arch/arm/boot/dts/r8a7779.dtsi
arch/arm/boot/dts/r8a7790-lager.dts
arch/arm/boot/dts/r8a7790.dtsi
arch/arm/boot/dts/r8a7791-koelsch.dts
arch/arm/boot/dts/r8a7791.dtsi
arch/arm/boot/dts/r8a77xx-aa104xd12-panel.dtsi [new file with mode: 0644]
arch/arm/boot/dts/sun6i-a31.dtsi
arch/arm/boot/dts/tegra114-dalmore.dts
arch/arm/boot/dts/tegra114-roth.dts
arch/arm/boot/dts/tegra114-tn7.dts
arch/arm/boot/dts/tegra114.dtsi
arch/arm/boot/dts/tegra124-jetson-tk1.dts
arch/arm/boot/dts/tegra124-nyan-big.dts
arch/arm/boot/dts/tegra124-venice2.dts
arch/arm/boot/dts/tegra124.dtsi
arch/arm/boot/dts/tegra20-harmony.dts
arch/arm/boot/dts/tegra20-iris-512.dts
arch/arm/boot/dts/tegra20-medcom-wide.dts
arch/arm/boot/dts/tegra20-paz00.dts
arch/arm/boot/dts/tegra20-seaboard.dts
arch/arm/boot/dts/tegra20-tamonten.dtsi
arch/arm/boot/dts/tegra20-trimslice.dts
arch/arm/boot/dts/tegra20-ventana.dts
arch/arm/boot/dts/tegra20-whistler.dts
arch/arm/boot/dts/tegra20.dtsi
arch/arm/boot/dts/tegra30-apalis-eval.dts
arch/arm/boot/dts/tegra30-beaver.dts
arch/arm/boot/dts/tegra30-cardhu.dtsi
arch/arm/boot/dts/tegra30-colibri-eval-v3.dts
arch/arm/boot/dts/tegra30.dtsi
arch/arm/configs/exynos_defconfig
arch/arm/configs/multi_v7_defconfig
arch/arm/include/asm/thread_info.h
arch/arm/kernel/traps.c
arch/arm/kvm/mmu.c
arch/arm/mach-mvebu/coherency.c
arch/arm/mach-shmobile/board-ape6evm-reference.c
arch/arm/mach-shmobile/board-ape6evm.c
arch/arm/mach-shmobile/board-armadillo800eva.c
arch/arm/mach-shmobile/board-bockw-reference.c
arch/arm/mach-shmobile/board-bockw.c
arch/arm/mach-shmobile/board-koelsch-reference.c
arch/arm/mach-shmobile/board-koelsch.c
arch/arm/mach-shmobile/board-kzm9g-reference.c
arch/arm/mach-shmobile/board-kzm9g.c
arch/arm/mach-shmobile/board-lager-reference.c
arch/arm/mach-shmobile/board-lager.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-shmobile/board-marzen-reference.c
arch/arm/mach-shmobile/board-marzen.c
arch/arm/mach-shmobile/clock-r8a73a4.c
arch/arm/mach-shmobile/clock-r8a7740.c
arch/arm/mach-shmobile/clock-r8a7778.c
arch/arm/mach-shmobile/clock-r8a7779.c
arch/arm/mach-shmobile/clock-r8a7790.c
arch/arm/mach-shmobile/clock-r8a7791.c
arch/arm/mach-shmobile/clock-sh7372.c
arch/arm/mach-shmobile/clock-sh73a0.c
arch/arm/mach-shmobile/clock.c
arch/arm/mach-shmobile/console.c
arch/arm/mach-shmobile/headsmp-scu.S
arch/arm/mach-shmobile/intc-sh7372.c
arch/arm/mach-shmobile/intc-sh73a0.c
arch/arm/mach-shmobile/r8a7740.h
arch/arm/mach-shmobile/r8a7778.h
arch/arm/mach-shmobile/setup-emev2.c
arch/arm/mach-shmobile/setup-r7s72100.c
arch/arm/mach-shmobile/setup-r8a73a4.c
arch/arm/mach-shmobile/setup-r8a7740.c
arch/arm/mach-shmobile/setup-r8a7778.c
arch/arm/mach-shmobile/setup-r8a7779.c
arch/arm/mach-shmobile/setup-r8a7790.c
arch/arm/mach-shmobile/setup-r8a7791.c
arch/arm/mach-shmobile/setup-rcar-gen2.c
arch/arm/mach-shmobile/setup-sh7372.c
arch/arm/mach-shmobile/setup-sh73a0.c
arch/arm/mach-shmobile/sleep-sh7372.S
arch/arm/mach-shmobile/smp-emev2.c
arch/arm/mach-shmobile/smp-r8a7779.c
arch/arm/mach-shmobile/smp-sh73a0.c
arch/arm/mach-shmobile/timer.c
arch/arm/mach-tegra/irq.c
arch/arm/mm/proc-v7.S
arch/arm/mm/proc-xscale.S
arch/arm64/kvm/sys_regs.c
arch/ia64/kvm/kvm-ia64.c
arch/mips/Kconfig
arch/mips/include/asm/jump_label.h
arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h
arch/mips/include/asm/mipsregs.h
arch/mips/include/asm/r4kcache.h
arch/mips/include/asm/uaccess.h
arch/mips/include/uapi/asm/unistd.h
arch/mips/kernel/bmips_vec.S
arch/mips/kernel/cps-vec.S
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/jump_label.c
arch/mips/kernel/rtlx.c
arch/mips/kernel/setup.c
arch/mips/kernel/signal.c
arch/mips/lib/memcpy.S
arch/mips/loongson/common/Makefile
arch/mips/loongson/loongson-3/numa.c
arch/mips/mm/tlb-r4k.c
arch/mips/mm/tlbex.c
arch/mips/mti-sead3/sead3-leds.c
arch/mips/netlogic/xlp/Makefile
arch/mips/oprofile/backtrace.c
arch/mips/sgi-ip27/ip27-memory.c
arch/powerpc/include/asm/pci-bridge.h
arch/powerpc/kernel/eeh_sysfs.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/vdso32/getcpu.S
arch/powerpc/platforms/powernv/opal-hmi.c
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/powernv/pci.c
arch/powerpc/platforms/pseries/msi.c
arch/powerpc/sysdev/fsl_msi.c
arch/powerpc/xmon/xmon.c
arch/sparc/include/asm/dma-mapping.h
arch/x86/Kconfig
arch/x86/include/asm/page_32_types.h
arch/x86/include/asm/page_64_types.h
arch/x86/include/asm/thread_info.h
arch/x86/include/asm/traps.h
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/microcode/core.c
arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c
arch/x86/kernel/dumpstack_64.c
arch/x86/kernel/entry_64.S
arch/x86/kernel/ptrace.c
arch/x86/kernel/traps.c
arch/x86/kvm/mmu.c
arch/x86/mm/init_64.c
arch/x86/tools/calc_run_size.pl
drivers/acpi/device_pm.c
drivers/atm/solos-pci.c
drivers/clk/at91/clk-usb.c
drivers/clk/clk-divider.c
drivers/clk/pxa/clk-pxa27x.c
drivers/clk/qcom/mmcc-apq8084.c
drivers/clk/rockchip/clk.c
drivers/clocksource/sun4i_timer.c
drivers/dma/pl330.c
drivers/dma/sun6i-dma.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/amd/amdkfd/Kconfig [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/cik_regs.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_crat.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_device.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_module.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_pasid.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_pm4_opcodes.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_priv.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_process.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_queue.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_topology.c [new file with mode: 0644]
drivers/gpu/drm/amd/amdkfd/kfd_topology.h [new file with mode: 0644]
drivers/gpu/drm/amd/include/kgd_kfd_interface.h [new file with mode: 0644]
drivers/gpu/drm/bochs/bochs_fbdev.c
drivers/gpu/drm/bochs/bochs_hw.c
drivers/gpu/drm/bochs/bochs_kms.c
drivers/gpu/drm/cirrus/cirrus_drv.h
drivers/gpu/drm/cirrus/cirrus_fbdev.c
drivers/gpu/drm/cirrus/cirrus_main.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_edid_load.c
drivers/gpu/drm/drm_flip_work.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_gem_cma_helper.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_mipi_dsi.c
drivers/gpu/drm/drm_modeset_lock.c
drivers/gpu/drm/drm_plane_helper.c
drivers/gpu/drm/drm_prime.c
drivers/gpu/drm/exynos/exynos_dp_core.c
drivers/gpu/drm/exynos/exynos_dp_core.h
drivers/gpu/drm/exynos/exynos_drm_crtc.h
drivers/gpu/drm/exynos/exynos_drm_dpi.c
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_dsi.c
drivers/gpu/drm/exynos/exynos_drm_encoder.h
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_iommu.h
drivers/gpu/drm/exynos/exynos_drm_ipp.c
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/gma500/Makefile
drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c
drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.h
drivers/gpu/drm/gma500/oaktrail_lvds.c
drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c [new file with mode: 0644]
drivers/gpu/drm/gma500/psb_drv.c
drivers/gpu/drm/gma500/psb_drv.h
drivers/gpu/drm/gma500/psb_intel_drv.h
drivers/gpu/drm/i2c/Kconfig
drivers/gpu/drm/i2c/Makefile
drivers/gpu/drm/i2c/adv7511.c [new file with mode: 0644]
drivers/gpu/drm/i2c/adv7511.h [new file with mode: 0644]
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_dp_mst.c
drivers/gpu/drm/imx/Kconfig [new file with mode: 0644]
drivers/gpu/drm/imx/Makefile [new file with mode: 0644]
drivers/gpu/drm/imx/imx-drm-core.c [new file with mode: 0644]
drivers/gpu/drm/imx/imx-drm.h [new file with mode: 0644]
drivers/gpu/drm/imx/imx-hdmi.c [new file with mode: 0644]
drivers/gpu/drm/imx/imx-hdmi.h [new file with mode: 0644]
drivers/gpu/drm/imx/imx-ldb.c [new file with mode: 0644]
drivers/gpu/drm/imx/imx-tve.c [new file with mode: 0644]
drivers/gpu/drm/imx/ipuv3-crtc.c [new file with mode: 0644]
drivers/gpu/drm/imx/ipuv3-plane.c [new file with mode: 0644]
drivers/gpu/drm/imx/ipuv3-plane.h [new file with mode: 0644]
drivers/gpu/drm/imx/parallel-display.c [new file with mode: 0644]
drivers/gpu/drm/msm/Kconfig
drivers/gpu/drm/msm/Makefile
drivers/gpu/drm/msm/adreno/a2xx.xml.h
drivers/gpu/drm/msm/adreno/a3xx.xml.h
drivers/gpu/drm/msm/adreno/a3xx_gpu.c
drivers/gpu/drm/msm/adreno/a4xx.xml.h [new file with mode: 0644]
drivers/gpu/drm/msm/adreno/a4xx_gpu.c [new file with mode: 0644]
drivers/gpu/drm/msm/adreno/a4xx_gpu.h [new file with mode: 0644]
drivers/gpu/drm/msm/adreno/adreno_common.xml.h
drivers/gpu/drm/msm/adreno/adreno_device.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/adreno/adreno_gpu.h
drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h
drivers/gpu/drm/msm/dsi/dsi.xml.h
drivers/gpu/drm/msm/dsi/mmss_cc.xml.h
drivers/gpu/drm/msm/dsi/sfpb.xml.h
drivers/gpu/drm/msm/hdmi/hdmi.c
drivers/gpu/drm/msm/hdmi/hdmi.h
drivers/gpu/drm/msm/hdmi/hdmi.xml.h
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
drivers/gpu/drm/msm/hdmi/hdmi_connector.c
drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c
drivers/gpu/drm/msm/hdmi/qfprom.xml.h
drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h
drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h
drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h
drivers/gpu/drm/msm/msm_atomic.c [new file with mode: 0644]
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/msm_fb.c
drivers/gpu/drm/msm/msm_fbdev.c
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_gem.h
drivers/gpu/drm/msm/msm_gem_prime.c
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/core/core/handle.c
drivers/gpu/drm/nouveau/core/engine/device/base.c
drivers/gpu/drm/nouveau/core/engine/device/gm100.c
drivers/gpu/drm/nouveau/core/engine/device/nve0.c
drivers/gpu/drm/nouveau/core/engine/disp/dport.c
drivers/gpu/drm/nouveau/core/engine/disp/gm107.c
drivers/gpu/drm/nouveau/core/engine/disp/gm204.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
drivers/gpu/drm/nouveau/core/engine/disp/outp.c
drivers/gpu/drm/nouveau/core/engine/disp/sorgm204.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c
drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c
drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
drivers/gpu/drm/nouveau/core/include/core/device.h
drivers/gpu/drm/nouveau/core/include/core/handle.h
drivers/gpu/drm/nouveau/core/include/core/object.h
drivers/gpu/drm/nouveau/core/include/engine/disp.h
drivers/gpu/drm/nouveau/core/include/subdev/bios/M0203.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h
drivers/gpu/drm/nouveau/core/include/subdev/bios/image.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/bios/npde.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/bios/pcir.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/bios/pmu.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h
drivers/gpu/drm/nouveau/core/include/subdev/devinit.h
drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
drivers/gpu/drm/nouveau/core/include/subdev/pwr.h
drivers/gpu/drm/nouveau/core/include/subdev/volt.h
drivers/gpu/drm/nouveau/core/os.h
drivers/gpu/drm/nouveau/core/subdev/bios/M0203.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/base.c
drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
drivers/gpu/drm/nouveau/core/subdev/bios/disp.c
drivers/gpu/drm/nouveau/core/subdev/bios/dp.c
drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c
drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c
drivers/gpu/drm/nouveau/core/subdev/bios/image.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/init.c
drivers/gpu/drm/nouveau/core/subdev/bios/npde.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/pcir.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/pmu.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/priv.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c
drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c
drivers/gpu/drm/nouveau/core/subdev/bios/shadow.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/shadowacpi.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/shadowof.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/shadowpci.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/shadowramin.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/shadowrom.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/timing.c
drivers/gpu/drm/nouveau/core/subdev/clock/gk20a.c
drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c
drivers/gpu/drm/nouveau/core/subdev/devinit/base.c
drivers/gpu/drm/nouveau/core/subdev/devinit/gm107.c
drivers/gpu/drm/nouveau/core/subdev/devinit/gm204.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h
drivers/gpu/drm/nouveau/core/subdev/devinit/nv84.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv98.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nvaf.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h
drivers/gpu/drm/nouveau/core/subdev/fb/base.c
drivers/gpu/drm/nouveau/core/subdev/fb/gddr3.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h
drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c
drivers/gpu/drm/nouveau/core/subdev/fb/sddr2.c
drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c
drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
drivers/gpu/drm/nouveau/core/subdev/i2c/gm204.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h
drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c
drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c
drivers/gpu/drm/nouveau/core/subdev/i2c/padgm204.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/memx.fuc
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/os.h
drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c
drivers/gpu/drm/nouveau/core/subdev/volt/base.c
drivers/gpu/drm/nouveau/core/subdev/volt/gk20a.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/dispnv04/crtc.c
drivers/gpu/drm/nouveau/dispnv04/overlay.c
drivers/gpu/drm/nouveau/nouveau_abi16.c
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_bo.h
drivers/gpu/drm/nouveau/nouveau_chan.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nouveau_platform.c
drivers/gpu/drm/nouveau/nouveau_platform.h
drivers/gpu/drm/nouveau/nouveau_prime.c
drivers/gpu/drm/nouveau/nv17_fence.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_fence.c
drivers/gpu/drm/nouveau/nv84_fence.c
drivers/gpu/drm/nouveau/nvif/class.h
drivers/gpu/drm/nouveau/nvif/client.c
drivers/gpu/drm/nouveau/nvif/driver.h
drivers/gpu/drm/omapdrm/omap_gem.c
drivers/gpu/drm/omapdrm/omap_plane.c
drivers/gpu/drm/panel/Kconfig
drivers/gpu/drm/panel/Makefile
drivers/gpu/drm/panel/panel-ld9040.c
drivers/gpu/drm/panel/panel-s6e8aa0.c
drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c [new file with mode: 0644]
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/qxl/qxl_display.c
drivers/gpu/drm/r128/r128_state.c
drivers/gpu/drm/radeon/Makefile
drivers/gpu/drm/radeon/ci_dpm.c
drivers/gpu/drm/radeon/ci_dpm.h
drivers/gpu/drm/radeon/ci_smc.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cik_reg.h
drivers/gpu/drm/radeon/cik_sdma.c
drivers/gpu/drm/radeon/cikd.h
drivers/gpu/drm/radeon/evergreen_dma.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/ni_dma.c
drivers/gpu/drm/radeon/ppsmc.h
drivers/gpu/drm/radeon/pptable.h
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_dma.c
drivers/gpu/drm/radeon/r600_dpm.c
drivers/gpu/drm/radeon/r600_dpm.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_cursor.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_fence.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_ib.c
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/radeon/radeon_kfd.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_kfd.h [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_object.h
drivers/gpu/drm/radeon/radeon_semaphore.c
drivers/gpu/drm/radeon/radeon_sync.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/radeon_vm.c
drivers/gpu/drm/radeon/rv770_dma.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dma.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/radeon/si_dpm.h
drivers/gpu/drm/radeon/si_smc.c
drivers/gpu/drm/radeon/sid.h
drivers/gpu/drm/radeon/sislands_smc.h
drivers/gpu/drm/radeon/smu7_discrete.h
drivers/gpu/drm/rcar-du/Kconfig
drivers/gpu/drm/rcar-du/Makefile
drivers/gpu/drm/rcar-du/rcar_du_crtc.c
drivers/gpu/drm/rcar-du/rcar_du_crtc.h
drivers/gpu/drm/rcar-du/rcar_du_drv.c
drivers/gpu/drm/rcar-du/rcar_du_drv.h
drivers/gpu/drm/rcar-du/rcar_du_encoder.c
drivers/gpu/drm/rcar-du/rcar_du_encoder.h
drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c [new file with mode: 0644]
drivers/gpu/drm/rcar-du/rcar_du_hdmicon.h [new file with mode: 0644]
drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c [new file with mode: 0644]
drivers/gpu/drm/rcar-du/rcar_du_hdmienc.h [new file with mode: 0644]
drivers/gpu/drm/rcar-du/rcar_du_kms.c
drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c
drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h
drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h
drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
drivers/gpu/drm/tegra/Kconfig
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/drm.h
drivers/gpu/drm/tegra/dsi.c
drivers/gpu/drm/tegra/dsi.h
drivers/gpu/drm/tegra/fb.c
drivers/gpu/drm/tegra/gem.c
drivers/gpu/drm/tegra/gem.h
drivers/gpu/drm/tegra/output.c
drivers/gpu/drm/tilcdc/tilcdc_crtc.c
drivers/gpu/drm/tilcdc/tilcdc_drv.c
drivers/gpu/drm/ttm/ttm_bo_manager.c
drivers/gpu/drm/ttm/ttm_page_alloc.c
drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
drivers/gpu/drm/udl/Makefile
drivers/gpu/drm/udl/udl_dmabuf.c [new file with mode: 0644]
drivers/gpu/drm/udl/udl_drv.c
drivers/gpu/drm/udl/udl_drv.h
drivers/gpu/drm/udl/udl_gem.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/host1x/cdma.c
drivers/gpu/host1x/cdma.h
drivers/gpu/host1x/hw/cdma_hw.c
drivers/gpu/host1x/hw/channel_hw.c
drivers/gpu/host1x/hw/debug_hw.c
drivers/gpu/host1x/job.h
drivers/gpu/host1x/mipi.c
drivers/hwmon/g762.c
drivers/iio/accel/bmc150-accel.c
drivers/iio/accel/kxcjk-1013.c
drivers/iio/adc/men_z188_adc.c
drivers/iio/gyro/bmg160.c
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/input/joystick/xpad.c
drivers/input/mouse/elantech.c
drivers/input/mouse/synaptics.c
drivers/iommu/amd_iommu_v2.c
drivers/irqchip/irq-atmel-aic-common.c
drivers/irqchip/irq-bcm7120-l2.c
drivers/irqchip/irq-brcmstb-l2.c
drivers/net/bonding/bond_main.c
drivers/net/can/dev.c
drivers/net/can/m_can/Kconfig
drivers/net/can/m_can/m_can.c
drivers/net/can/rcar_can.c
drivers/net/can/sja1000/kvaser_pci.c
drivers/net/can/usb/ems_usb.c
drivers/net/can/usb/esd_usb2.c
drivers/net/can/usb/gs_usb.c
drivers/net/can/xilinx_can.c
drivers/net/dsa/bcm_sf2.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ieee802154/fakehard.c
drivers/net/ppp/pptp.c
drivers/net/usb/qmi_wwan.c
drivers/net/virtio_net.c
drivers/net/vxlan.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/b43/phy_common.c
drivers/net/wireless/brcm80211/brcmfmac/of.c
drivers/net/wireless/brcm80211/brcmfmac/pcie.c
drivers/net/wireless/brcm80211/brcmfmac/usb.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/rtl8192se/hw.c
drivers/net/wireless/rtlwifi/rtl8192se/phy.c
drivers/net/wireless/rtlwifi/rtl8192se/sw.c
drivers/net/wireless/rtlwifi/rtl8821ae/hw.c
drivers/net/xen-netback/xenbus.c
drivers/of/address.c
drivers/of/dynamic.c
drivers/of/fdt.c
drivers/of/selftest.c
drivers/pci/access.c
drivers/pci/host/pci-xgene.c
drivers/pci/msi.c
drivers/pci/pci.h
drivers/pci/probe.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
drivers/scsi/cxgbi/libcxgbi.c
drivers/scsi/scsi_devinfo.c
drivers/scsi/ufs/ufshcd-pltfrm.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h
drivers/soc/tegra/fuse/fuse-tegra.c
drivers/spi/spi-dw.c
drivers/spi/spi-sirf.c
drivers/spi/spi.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/imx-drm/Kconfig [deleted file]
drivers/staging/imx-drm/Makefile [deleted file]
drivers/staging/imx-drm/TODO [deleted file]
drivers/staging/imx-drm/imx-drm-core.c [deleted file]
drivers/staging/imx-drm/imx-drm.h [deleted file]
drivers/staging/imx-drm/imx-hdmi.c [deleted file]
drivers/staging/imx-drm/imx-hdmi.h [deleted file]
drivers/staging/imx-drm/imx-ldb.c [deleted file]
drivers/staging/imx-drm/imx-tve.c [deleted file]
drivers/staging/imx-drm/ipuv3-crtc.c [deleted file]
drivers/staging/imx-drm/ipuv3-plane.c [deleted file]
drivers/staging/imx-drm/ipuv3-plane.h [deleted file]
drivers/staging/imx-drm/parallel-display.c [deleted file]
drivers/staging/rtl8188eu/core/rtw_cmd.c
drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
drivers/staging/rtl8188eu/core/rtw_wlan_util.c
drivers/staging/rtl8188eu/os_dep/usb_intf.c
drivers/target/iscsi/iscsi_target.c
drivers/target/target_core_pr.c
drivers/target/target_core_transport.c
drivers/thermal/cpu_cooling.c
drivers/thermal/samsung/exynos_thermal_common.c
drivers/thermal/st/st_thermal.c
drivers/tty/serial/of_serial.c
drivers/usb/core/quirks.c
drivers/usb/dwc3/ep0.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-plat.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/serial/cp210x.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/keyspan.c
drivers/usb/serial/ssu100.c
drivers/usb/storage/unusual_uas.h
drivers/vhost/scsi.c
fs/Makefile
fs/aio.c
fs/btrfs/compression.c
fs/btrfs/compression.h
fs/btrfs/ctree.c
fs/btrfs/locking.c
fs/btrfs/locking.h
fs/btrfs/lzo.c
fs/btrfs/zlib.c
fs/dcache.c
fs/isofs/inode.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfsd.h
fs/overlayfs/Kconfig
fs/overlayfs/Makefile
fs/overlayfs/dir.c
fs/overlayfs/inode.c
fs/overlayfs/readdir.c
fs/overlayfs/super.c
include/drm/drmP.h
include/drm/drm_atomic.h
include/drm/drm_atomic_helper.h
include/drm/drm_crtc.h
include/drm/drm_dp_mst_helper.h
include/drm/drm_edid.h
include/drm/drm_flip_work.h
include/drm/drm_gem.h
include/drm/drm_gem_cma_helper.h
include/drm/drm_mipi_dsi.h
include/drm/drm_modeset_lock.h
include/drm/drm_plane_helper.h
include/dt-bindings/clock/qcom,mmcc-apq8084.h
include/linux/bitops.h
include/linux/can/dev.h
include/linux/clk-provider.h
include/linux/hdmi.h
include/linux/iio/events.h
include/linux/inetdevice.h
include/linux/kernel_stat.h
include/linux/kvm_host.h
include/linux/mmu_notifier.h
include/linux/pci.h
include/linux/percpu-refcount.h
include/linux/platform_data/rcar-du.h [deleted file]
include/net/inet_common.h
include/net/netfilter/nf_tables.h
include/net/vxlan.h
include/sound/pcm.h
include/sound/soc-dpcm.h
include/trace/events/host1x.h
include/uapi/drm/drm_mode.h
include/uapi/linux/kfd_ioctl.h [new file with mode: 0644]
include/uapi/sound/asound.h
kernel/events/core.c
kernel/events/uprobes.c
kernel/sched/core.c
kernel/sched/deadline.c
kernel/sched/fair.c
kernel/sched/idle_task.c
kernel/sched/rt.c
kernel/sched/sched.h
kernel/sched/stop_task.c
kernel/time/posix-cpu-timers.c
lib/Makefile
mm/fremap.c
mm/huge_memory.c
mm/hugetlb.c
mm/ksm.c
mm/memory.c
mm/migrate.c
mm/mmu_notifier.c
mm/rmap.c
net/bridge/br_multicast.c
net/bridge/br_netlink.c
net/core/rtnetlink.c
net/core/skbuff.c
net/dcb/dcbnl.c
net/ipv4/af_inet.c
net/ipv4/fib_rules.c
net/ipv4/igmp.c
net/ipv4/ip_vti.c
net/ipv4/netfilter/nft_masq_ipv4.c
net/ipv4/ping.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv6/ip6_gre.c
net/ipv6/ip6_offload.c
net/ipv6/ip6_udp_tunnel.c
net/ipv6/ip6_vti.c
net/ipv6/ip6mr.c
net/ipv6/mcast.c
net/ipv6/netfilter/nft_masq_ipv6.c
net/ipv6/tcp_ipv6.c
net/ipx/af_ipx.c
net/mac80211/aes_ccm.c
net/mac80211/rc80211_minstrel_ht.c
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipvs/ip_vs_xmit.c
net/netfilter/nf_tables_api.c
net/netfilter/nfnetlink.c
net/netfilter/nft_compat.c
net/openvswitch/actions.c
net/openvswitch/datapath.c
net/openvswitch/flow_netlink.c
net/packet/af_packet.c
net/sunrpc/svcsock.c
sound/core/pcm.c
sound/core/pcm_misc.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_priv.h
sound/pci/hda/patch_realtek.c
sound/soc/codecs/cs42l51-i2c.c
sound/soc/codecs/cs42l51.c
sound/soc/codecs/cs42l51.h
sound/soc/codecs/es8328-i2c.c
sound/soc/codecs/max98090.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5670.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sgtl5000.h
sound/soc/codecs/wm_adsp.c
sound/soc/fsl/fsl_asrc.c
sound/soc/rockchip/rockchip_i2s.c
sound/soc/samsung/snow.c
sound/soc/sh/fsi.c
sound/soc/sh/rcar/core.c
sound/soc/soc-core.c
sound/soc/soc-pcm.c
sound/usb/mixer.c
sound/usb/mixer_quirks.c
sound/usb/quirks.c
virt/kvm/arm/vgic.c
virt/kvm/kvm_main.c

diff --git a/CREDITS b/CREDITS
index bb6278884f894878dc49e1c6722a0cbe3e89e82e..c56d8aa10131d8443f7c5b717ae2b13b2a1d376b 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1197,6 +1197,13 @@ S: R. Tocantins, 89 - Cristo Rei
 S: 80050-430 - Curitiba - Paraná
 S: Brazil
 
+N: Oded Gabbay
+E: oded.gabbay@gmail.com
+D: AMD KFD maintainer
+S: 12 Shraga Raphaeli
+S: Petah-Tikva, 4906418
+S: Israel
+
 N: Kumar Gala
 E: galak@kernel.crashing.org
 D: Embedded PowerPC 6xx/7xx/74xx/82xx/83xx/85xx support
index a1168a8e2279730c5ef97096b5ea570ccc49d950..56e2a9b65c6857b1788592c985d7aa56180b15c4 100644 (file)
@@ -492,10 +492,10 @@ char *date;</synopsis>
     <sect2>
       <title>The Translation Table Manager (TTM)</title>
       <para>
-       TTM design background and information belongs here.
+        TTM design background and information belongs here.
       </para>
       <sect3>
-       <title>TTM initialization</title>
+        <title>TTM initialization</title>
         <warning><para>This section is outdated.</para></warning>
         <para>
           Drivers wishing to support TTM must fill out a drm_bo_driver
@@ -503,42 +503,42 @@ char *date;</synopsis>
           pointers for initializing the TTM, allocating and freeing memory,
           waiting for command completion and fence synchronization, and memory
           migration. See the radeon_ttm.c file for an example of usage.
-       </para>
-       <para>
-         The ttm_global_reference structure is made up of several fields:
-       </para>
-       <programlisting>
-         struct ttm_global_reference {
-               enum ttm_global_types global_type;
-               size_t size;
-               void *object;
-               int (*init) (struct ttm_global_reference *);
-               void (*release) (struct ttm_global_reference *);
-         };
-       </programlisting>
-       <para>
-         There should be one global reference structure for your memory
-         manager as a whole, and there will be others for each object
-         created by the memory manager at runtime.  Your global TTM should
-         have a type of TTM_GLOBAL_TTM_MEM.  The size field for the global
-         object should be sizeof(struct ttm_mem_global), and the init and
-         release hooks should point at your driver-specific init and
-         release routines, which probably eventually call
-         ttm_mem_global_init and ttm_mem_global_release, respectively.
-       </para>
-       <para>
-         Once your global TTM accounting structure is set up and initialized
-         by calling ttm_global_item_ref() on it,
-         you need to create a buffer object TTM to
-         provide a pool for buffer object allocation by clients and the
-         kernel itself.  The type of this object should be TTM_GLOBAL_TTM_BO,
-         and its size should be sizeof(struct ttm_bo_global).  Again,
-         driver-specific init and release functions may be provided,
-         likely eventually calling ttm_bo_global_init() and
-         ttm_bo_global_release(), respectively.  Also, like the previous
-         object, ttm_global_item_ref() is used to create an initial reference
-         count for the TTM, which will call your initialization function.
-       </para>
+        </para>
+        <para>
+          The ttm_global_reference structure is made up of several fields:
+        </para>
+        <programlisting>
+          struct ttm_global_reference {
+                  enum ttm_global_types global_type;
+                  size_t size;
+                  void *object;
+                  int (*init) (struct ttm_global_reference *);
+                  void (*release) (struct ttm_global_reference *);
+          };
+        </programlisting>
+        <para>
+          There should be one global reference structure for your memory
+          manager as a whole, and there will be others for each object
+          created by the memory manager at runtime.  Your global TTM should
+          have a type of TTM_GLOBAL_TTM_MEM.  The size field for the global
+          object should be sizeof(struct ttm_mem_global), and the init and
+          release hooks should point at your driver-specific init and
+          release routines, which probably eventually call
+          ttm_mem_global_init and ttm_mem_global_release, respectively.
+        </para>
+        <para>
+          Once your global TTM accounting structure is set up and initialized
+          by calling ttm_global_item_ref() on it,
+          you need to create a buffer object TTM to
+          provide a pool for buffer object allocation by clients and the
+          kernel itself.  The type of this object should be TTM_GLOBAL_TTM_BO,
+          and its size should be sizeof(struct ttm_bo_global).  Again,
+          driver-specific init and release functions may be provided,
+          likely eventually calling ttm_bo_global_init() and
+          ttm_bo_global_release(), respectively.  Also, like the previous
+          object, ttm_global_item_ref() is used to create an initial reference
+          count for the TTM, which will call your initialization function.
+        </para>
       </sect3>
     </sect2>
     <sect2 id="drm-gem">
@@ -566,19 +566,19 @@ char *date;</synopsis>
         using driver-specific ioctls.
       </para>
       <para>
-       On a fundamental level, GEM involves several operations:
-       <itemizedlist>
-         <listitem>Memory allocation and freeing</listitem>
-         <listitem>Command execution</listitem>
-         <listitem>Aperture management at command execution time</listitem>
-       </itemizedlist>
-       Buffer object allocation is relatively straightforward and largely
+        On a fundamental level, GEM involves several operations:
+        <itemizedlist>
+          <listitem>Memory allocation and freeing</listitem>
+          <listitem>Command execution</listitem>
+          <listitem>Aperture management at command execution time</listitem>
+        </itemizedlist>
+        Buffer object allocation is relatively straightforward and largely
         provided by Linux's shmem layer, which provides memory to back each
         object.
       </para>
       <para>
         Device-specific operations, such as command execution, pinning, buffer
-       read &amp; write, mapping, and domain ownership transfers are left to
+        read &amp; write, mapping, and domain ownership transfers are left to
         driver-specific ioctls.
       </para>
       <sect3>
@@ -738,16 +738,16 @@ char *date;</synopsis>
           respectively. The conversion is handled by the DRM core without any
           driver-specific support.
         </para>
-       <para>
-         GEM also supports buffer sharing with dma-buf file descriptors through
-         PRIME. GEM-based drivers must use the provided helpers functions to
-         implement the exporting and importing correctly. See <xref linkend="drm-prime-support" />.
-         Since sharing file descriptors is inherently more secure than the
-         easily guessable and global GEM names it is the preferred buffer
-         sharing mechanism. Sharing buffers through GEM names is only supported
-         for legacy userspace. Furthermore PRIME also allows cross-device
-         buffer sharing since it is based on dma-bufs.
-       </para>
+        <para>
+          GEM also supports buffer sharing with dma-buf file descriptors through
+          PRIME. GEM-based drivers must use the provided helpers functions to
+          implement the exporting and importing correctly. See <xref linkend="drm-prime-support" />.
+          Since sharing file descriptors is inherently more secure than the
+          easily guessable and global GEM names it is the preferred buffer
+          sharing mechanism. Sharing buffers through GEM names is only supported
+          for legacy userspace. Furthermore PRIME also allows cross-device
+          buffer sharing since it is based on dma-bufs.
+        </para>
       </sect3>
       <sect3 id="drm-gem-objects-mapping">
         <title>GEM Objects Mapping</title>
@@ -852,7 +852,7 @@ char *date;</synopsis>
       <sect3>
         <title>Command Execution</title>
         <para>
-         Perhaps the most important GEM function for GPU devices is providing a
+          Perhaps the most important GEM function for GPU devices is providing a
           command execution interface to clients. Client programs construct
           command buffers containing references to previously allocated memory
           objects, and then submit them to GEM. At that point, GEM takes care to
@@ -874,95 +874,101 @@ char *date;</synopsis>
         <title>GEM Function Reference</title>
 !Edrivers/gpu/drm/drm_gem.c
       </sect3>
-      </sect2>
-      <sect2>
-       <title>VMA Offset Manager</title>
+    </sect2>
+    <sect2>
+      <title>VMA Offset Manager</title>
 !Pdrivers/gpu/drm/drm_vma_manager.c vma offset manager
 !Edrivers/gpu/drm/drm_vma_manager.c
 !Iinclude/drm/drm_vma_manager.h
-      </sect2>
-      <sect2 id="drm-prime-support">
-       <title>PRIME Buffer Sharing</title>
-       <para>
-         PRIME is the cross device buffer sharing framework in drm, originally
-         created for the OPTIMUS range of multi-gpu platforms. To userspace
-         PRIME buffers are dma-buf based file descriptors.
-       </para>
-       <sect3>
-         <title>Overview and Driver Interface</title>
-         <para>
-           Similar to GEM global names, PRIME file descriptors are
-           also used to share buffer objects across processes. They offer
-           additional security: as file descriptors must be explicitly sent over
-           UNIX domain sockets to be shared between applications, they can't be
-           guessed like the globally unique GEM names.
-         </para>
-         <para>
-           Drivers that support the PRIME
-           API must set the DRIVER_PRIME bit in the struct
-           <structname>drm_driver</structname>
-           <structfield>driver_features</structfield> field, and implement the
-           <methodname>prime_handle_to_fd</methodname> and
-           <methodname>prime_fd_to_handle</methodname> operations.
-         </para>
-         <para>
-           <synopsis>int (*prime_handle_to_fd)(struct drm_device *dev,
-                         struct drm_file *file_priv, uint32_t handle,
-                         uint32_t flags, int *prime_fd);
+    </sect2>
+    <sect2 id="drm-prime-support">
+      <title>PRIME Buffer Sharing</title>
+      <para>
+        PRIME is the cross device buffer sharing framework in drm, originally
+        created for the OPTIMUS range of multi-gpu platforms. To userspace
+        PRIME buffers are dma-buf based file descriptors.
+      </para>
+      <sect3>
+        <title>Overview and Driver Interface</title>
+        <para>
+          Similar to GEM global names, PRIME file descriptors are
+          also used to share buffer objects across processes. They offer
+          additional security: as file descriptors must be explicitly sent over
+          UNIX domain sockets to be shared between applications, they can't be
+          guessed like the globally unique GEM names.
+        </para>
+        <para>
+          Drivers that support the PRIME
+          API must set the DRIVER_PRIME bit in the struct
+          <structname>drm_driver</structname>
+          <structfield>driver_features</structfield> field, and implement the
+          <methodname>prime_handle_to_fd</methodname> and
+          <methodname>prime_fd_to_handle</methodname> operations.
+        </para>
+        <para>
+          <synopsis>int (*prime_handle_to_fd)(struct drm_device *dev,
+                          struct drm_file *file_priv, uint32_t handle,
+                          uint32_t flags, int *prime_fd);
 int (*prime_fd_to_handle)(struct drm_device *dev,
-                         struct drm_file *file_priv, int prime_fd,
-                         uint32_t *handle);</synopsis>
-           Those two operations convert a handle to a PRIME file descriptor and
-           vice versa. Drivers must use the kernel dma-buf buffer sharing framework
-           to manage the PRIME file descriptors. Similar to the mode setting
-           API PRIME is agnostic to the underlying buffer object manager, as
-           long as handles are 32bit unsigned integers.
-         </para>
-         <para>
-           While non-GEM drivers must implement the operations themselves, GEM
-           drivers must use the <function>drm_gem_prime_handle_to_fd</function>
-           and <function>drm_gem_prime_fd_to_handle</function> helper functions.
-           Those helpers rely on the driver
-           <methodname>gem_prime_export</methodname> and
-           <methodname>gem_prime_import</methodname> operations to create a dma-buf
-           instance from a GEM object (dma-buf exporter role) and to create a GEM
-           object from a dma-buf instance (dma-buf importer role).
-         </para>
-         <para>
-           <synopsis>struct dma_buf * (*gem_prime_export)(struct drm_device *dev,
-                                    struct drm_gem_object *obj,
-                                    int flags);
+                          struct drm_file *file_priv, int prime_fd,
+                          uint32_t *handle);</synopsis>
+            Those two operations convert a handle to a PRIME file descriptor and
+            vice versa. Drivers must use the kernel dma-buf buffer sharing framework
+            to manage the PRIME file descriptors. Similar to the mode setting
+            API PRIME is agnostic to the underlying buffer object manager, as
+            long as handles are 32bit unsigned integers.
+          </para>
+          <para>
+            While non-GEM drivers must implement the operations themselves, GEM
+            drivers must use the <function>drm_gem_prime_handle_to_fd</function>
+            and <function>drm_gem_prime_fd_to_handle</function> helper functions.
+            Those helpers rely on the driver
+            <methodname>gem_prime_export</methodname> and
+            <methodname>gem_prime_import</methodname> operations to create a dma-buf
+            instance from a GEM object (dma-buf exporter role) and to create a GEM
+            object from a dma-buf instance (dma-buf importer role).
+          </para>
+          <para>
+            <synopsis>struct dma_buf * (*gem_prime_export)(struct drm_device *dev,
+                             struct drm_gem_object *obj,
+                             int flags);
 struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev,
-                                           struct dma_buf *dma_buf);</synopsis>
-           These two operations are mandatory for GEM drivers that support
-           PRIME.
-         </para>
-       </sect3>
-        <sect3>
-          <title>PRIME Helper Functions</title>
-!Pdrivers/gpu/drm/drm_prime.c PRIME Helpers
+                                            struct dma_buf *dma_buf);</synopsis>
+            These two operations are mandatory for GEM drivers that support
+            PRIME.
+          </para>
         </sect3>
-      </sect2>
-      <sect2>
-       <title>PRIME Function References</title>
+      <sect3>
+        <title>PRIME Helper Functions</title>
+!Pdrivers/gpu/drm/drm_prime.c PRIME Helpers
+      </sect3>
+    </sect2>
+    <sect2>
+      <title>PRIME Function References</title>
 !Edrivers/gpu/drm/drm_prime.c
-      </sect2>
-      <sect2>
-       <title>DRM MM Range Allocator</title>
-       <sect3>
-         <title>Overview</title>
+    </sect2>
+    <sect2>
+      <title>DRM MM Range Allocator</title>
+      <sect3>
+        <title>Overview</title>
 !Pdrivers/gpu/drm/drm_mm.c Overview
-       </sect3>
-       <sect3>
-         <title>LRU Scan/Eviction Support</title>
+      </sect3>
+      <sect3>
+        <title>LRU Scan/Eviction Support</title>
 !Pdrivers/gpu/drm/drm_mm.c lru scan roaster
-       </sect3>
+      </sect3>
       </sect2>
-      <sect2>
-       <title>DRM MM Range Allocator Function References</title>
+    <sect2>
+      <title>DRM MM Range Allocator Function References</title>
 !Edrivers/gpu/drm/drm_mm.c
 !Iinclude/drm/drm_mm.h
-      </sect2>
+    </sect2>
+    <sect2>
+      <title>CMA Helper Functions Reference</title>
+!Pdrivers/gpu/drm/drm_gem_cma_helper.c cma helpers
+!Edrivers/gpu/drm/drm_gem_cma_helper.c
+!Iinclude/drm/drm_gem_cma_helper.h
+    </sect2>
   </sect1>
 
   <!-- Internals: mode setting -->
@@ -2337,6 +2343,7 @@ void intel_crt_init(struct drm_device *dev)
        <title>Atomic State Reset and Initialization</title>
 !Pdrivers/gpu/drm/drm_atomic_helper.c atomic state reset and initialization
       </sect3>
+!Iinclude/drm/drm_atomic_helper.h
 !Edrivers/gpu/drm/drm_atomic_helper.c
     </sect2>
     <sect2>
@@ -2366,6 +2373,12 @@ void intel_crt_init(struct drm_device *dev)
 !Pdrivers/gpu/drm/drm_dp_mst_topology.c dp mst helper
 !Iinclude/drm/drm_dp_mst_helper.h
 !Edrivers/gpu/drm/drm_dp_mst_topology.c
+    </sect2>
+    <sect2>
+      <title>MIPI DSI Helper Functions Reference</title>
+!Pdrivers/gpu/drm/drm_mipi_dsi.c dsi helpers
+!Iinclude/drm/drm_mipi_dsi.h
+!Edrivers/gpu/drm/drm_mipi_dsi.c
     </sect2>
     <sect2>
       <title>EDID Helper Functions Reference</title>
@@ -2533,7 +2546,7 @@ void intel_crt_init(struct drm_device *dev)
        <td valign="top" >Description/Restrictions</td>
        </tr>
        <tr>
-       <td rowspan="21" valign="top" >DRM</td>
+       <td rowspan="23" valign="top" >DRM</td>
        <td rowspan="3" valign="top" >Generic</td>
        <td valign="top" >“EDID”</td>
        <td valign="top" >BLOB | IMMUTABLE</td>
@@ -2671,6 +2684,21 @@ void intel_crt_init(struct drm_device *dev)
        <td valign="top" >TBD</td>
        </tr>
        <tr>
+       <td rowspan="2" valign="top" >Virtual GPU</td>
+       <td valign="top" >“suggested X”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=0xffffffff</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >property to suggest an X offset for a connector</td>
+       </tr>
+       <tr>
+       <td valign="top" >“suggested Y”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=0xffffffff</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >property to suggest an Y offset for a connector</td>
+       </tr>
+       <tr>
        <td rowspan="3" valign="top" >Optional</td>
        <td valign="top" >“scaling mode”</td>
        <td valign="top" >ENUM</td>
diff --git a/Documentation/devicetree/bindings/drm/imx/fsl-imx-drm.txt b/Documentation/devicetree/bindings/drm/imx/fsl-imx-drm.txt
new file mode 100644 (file)
index 0000000..e75f0e5
--- /dev/null
@@ -0,0 +1,83 @@
+Freescale i.MX DRM master device
+================================
+
+The freescale i.MX DRM master device is a virtual device needed to list all
+IPU or other display interface nodes that comprise the graphics subsystem.
+
+Required properties:
+- compatible: Should be "fsl,imx-display-subsystem"
+- ports: Should contain a list of phandles pointing to display interface ports
+  of IPU devices
+
+example:
+
+display-subsystem {
+       compatible = "fsl,display-subsystem";
+       ports = <&ipu_di0>;
+};
+
+
+Freescale i.MX IPUv3
+====================
+
+Required properties:
+- compatible: Should be "fsl,<chip>-ipu"
+- reg: should be register base and length as documented in the
+  datasheet
+- interrupts: Should contain sync interrupt and error interrupt,
+  in this order.
+- resets: phandle pointing to the system reset controller and
+          reset line index, see reset/fsl,imx-src.txt for details
+Optional properties:
+- port@[0-3]: Port nodes with endpoint definitions as defined in
+  Documentation/devicetree/bindings/media/video-interfaces.txt.
+  Ports 0 and 1 should correspond to CSI0 and CSI1,
+  ports 2 and 3 should correspond to DI0 and DI1, respectively.
+
+example:
+
+ipu: ipu@18000000 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       compatible = "fsl,imx53-ipu";
+       reg = <0x18000000 0x080000000>;
+       interrupts = <11 10>;
+       resets = <&src 2>;
+
+       ipu_di0: port@2 {
+               reg = <2>;
+
+               ipu_di0_disp0: endpoint {
+                       remote-endpoint = <&display_in>;
+               };
+       };
+};
+
+Parallel display support
+========================
+
+Required properties:
+- compatible: Should be "fsl,imx-parallel-display"
+Optional properties:
+- interface_pix_fmt: How this display is connected to the
+  display interface. Currently supported types: "rgb24", "rgb565", "bgr666"
+  and "lvds666".
+- edid: verbatim EDID data block describing attached display.
+- ddc: phandle describing the i2c bus handling the display data
+  channel
+- port: A port node with endpoint definitions as defined in
+  Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+example:
+
+display@di0 {
+       compatible = "fsl,imx-parallel-display";
+       edid = [edid-data];
+       interface-pix-fmt = "rgb24";
+
+       port {
+               display_in: endpoint {
+                       remote-endpoint = <&ipu_di0_disp0>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/drm/imx/hdmi.txt b/Documentation/devicetree/bindings/drm/imx/hdmi.txt
new file mode 100644 (file)
index 0000000..1b756cf
--- /dev/null
@@ -0,0 +1,58 @@
+Device-Tree bindings for HDMI Transmitter
+
+HDMI Transmitter
+================
+
+The HDMI Transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
+with accompanying PHY IP.
+
+Required properties:
+ - #address-cells : should be <1>
+ - #size-cells : should be <0>
+ - compatible : should be "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi".
+ - gpr : should be <&gpr>.
+   The phandle points to the iomuxc-gpr region containing the HDMI
+   multiplexer control register.
+ - clocks, clock-names : phandles to the HDMI iahb and isrf clocks, as described
+   in Documentation/devicetree/bindings/clock/clock-bindings.txt and
+   Documentation/devicetree/bindings/clock/imx6q-clock.txt.
+ - port@[0-4]: Up to four port nodes with endpoint definitions as defined in
+   Documentation/devicetree/bindings/media/video-interfaces.txt,
+   corresponding to the four inputs to the HDMI multiplexer.
+
+Optional properties:
+ - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+
+example:
+
+       gpr: iomuxc-gpr@020e0000 {
+               /* ... */
+       };
+
+        hdmi: hdmi@0120000 {
+                #address-cells = <1>;
+                #size-cells = <0>;
+                compatible = "fsl,imx6q-hdmi";
+                reg = <0x00120000 0x9000>;
+                interrupts = <0 115 0x04>;
+                gpr = <&gpr>;
+                clocks = <&clks 123>, <&clks 124>;
+                clock-names = "iahb", "isfr";
+                ddc-i2c-bus = <&i2c2>;
+
+                port@0 {
+                        reg = <0>;
+
+                        hdmi_mux_0: endpoint {
+                                remote-endpoint = <&ipu1_di0_hdmi>;
+                        };
+                };
+
+                port@1 {
+                        reg = <1>;
+
+                        hdmi_mux_1: endpoint {
+                                remote-endpoint = <&ipu1_di1_hdmi>;
+                        };
+                };
+        };
diff --git a/Documentation/devicetree/bindings/drm/imx/ldb.txt b/Documentation/devicetree/bindings/drm/imx/ldb.txt
new file mode 100644 (file)
index 0000000..443bcb6
--- /dev/null
@@ -0,0 +1,122 @@
+Device-Tree bindings for LVDS Display Bridge (ldb)
+
+LVDS Display Bridge
+===================
+
+The LVDS Display Bridge device tree node contains up to two lvds-channel
+nodes describing each of the two LVDS encoder channels of the bridge.
+
+Required properties:
+ - #address-cells : should be <1>
+ - #size-cells : should be <0>
+ - compatible : should be "fsl,imx53-ldb" or "fsl,imx6q-ldb".
+                Both LDB versions are similar, but i.MX6 has an additional
+                multiplexer in the front to select any of the four IPU display
+                interfaces as input for each LVDS channel.
+ - gpr : should be <&gpr> on i.MX53 and i.MX6q.
+         The phandle points to the iomuxc-gpr region containing the LVDS
+         control register.
+- clocks, clock-names : phandles to the LDB divider and selector clocks and to
+                        the display interface selector clocks, as described in
+                        Documentation/devicetree/bindings/clock/clock-bindings.txt
+        The following clocks are expected on i.MX53:
+                "di0_pll" - LDB LVDS channel 0 mux
+                "di1_pll" - LDB LVDS channel 1 mux
+                "di0" - LDB LVDS channel 0 gate
+                "di1" - LDB LVDS channel 1 gate
+                "di0_sel" - IPU1 DI0 mux
+                "di1_sel" - IPU1 DI1 mux
+        On i.MX6q the following additional clocks are needed:
+                "di2_sel" - IPU2 DI0 mux
+                "di3_sel" - IPU2 DI1 mux
+        The needed clock numbers for each are documented in
+        Documentation/devicetree/bindings/clock/imx5-clock.txt, and in
+        Documentation/devicetree/bindings/clock/imx6q-clock.txt.
+
+Optional properties:
+ - pinctrl-names : should be "default" on i.MX53, not used on i.MX6q
+ - pinctrl-0 : a phandle pointing to LVDS pin settings on i.MX53,
+               not used on i.MX6q
+ - fsl,dual-channel : boolean. if it exists, only LVDS channel 0 should
+   be configured - one input will be distributed on both outputs in dual
+   channel mode
+
+LVDS Channel
+============
+
+Each LVDS Channel has to contain a display-timings node that describes the
+video timings for the connected LVDS display. For detailed information, also
+have a look at Documentation/devicetree/bindings/video/display-timing.txt.
+
+Required properties:
+ - reg : should be <0> or <1>
+ - fsl,data-mapping : should be "spwg" or "jeida"
+                      This describes how the color bits are laid out in the
+                      serialized LVDS signal.
+ - fsl,data-width : should be <18> or <24>
+ - port: A port node with endpoint definitions as defined in
+   Documentation/devicetree/bindings/media/video-interfaces.txt.
+   On i.MX5, the internal two-input-multiplexer is used.
+   Due to hardware limitations, only one port (port@[0,1])
+   can be used for each channel (lvds-channel@[0,1], respectively)
+   On i.MX6, there should be four ports (port@[0-3]) that correspond
+   to the four LVDS multiplexer inputs.
+
+example:
+
+gpr: iomuxc-gpr@53fa8000 {
+       /* ... */
+};
+
+ldb: ldb@53fa8008 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       compatible = "fsl,imx53-ldb";
+       gpr = <&gpr>;
+       clocks = <&clks 122>, <&clks 120>,
+                <&clks 115>, <&clks 116>,
+                <&clks 123>, <&clks 85>;
+       clock-names = "di0_pll", "di1_pll",
+                     "di0_sel", "di1_sel",
+                     "di0", "di1";
+
+       lvds-channel@0 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0>;
+               fsl,data-mapping = "spwg";
+               fsl,data-width = <24>;
+
+               display-timings {
+                       /* ... */
+               };
+
+               port@0 {
+                       reg = <0>;
+
+                       lvds0_in: endpoint {
+                               remote-endpoint = <&ipu_di0_lvds0>;
+                       };
+               };
+       };
+
+       lvds-channel@1 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <1>;
+               fsl,data-mapping = "spwg";
+               fsl,data-width = <24>;
+
+               display-timings {
+                       /* ... */
+               };
+
+               port@1 {
+                       reg = <1>;
+
+                       lvds1_in: endpoint {
+                               remote-endpoint = <&ipu_di1_lvds1>;
+                       };
+               };
+       };
+};
index b48f4ef31d937ff8c4944e379d55357045653f02..4c32ef0b7db8fd635285b63722771a1a5ee9f848 100644 (file)
@@ -191,6 +191,8 @@ of the following host1x client modules:
   - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
   - nvidia,edid: supplies a binary EDID blob
   - nvidia,panel: phandle of a display panel
+  - nvidia,ganged-mode: contains a phandle to a second DSI controller to gang
+    up with in order to support up to 8 data lanes
 
 - sor: serial output resource
 
index ce6a1a0720285bd9be4549d478ea49b4b985ee31..8a3c4082989906248fd4f07ee7a1493b20580794 100644 (file)
@@ -30,10 +30,6 @@ should only be used when a device has multiple interrupt parents.
   Example:
        interrupts-extended = <&intc1 5 1>, <&intc2 1 0>;
 
-A device node may contain either "interrupts" or "interrupts-extended", but not
-both. If both properties are present, then the operating system should log an
-error and use only the data in "interrupts".
-
 2) Interrupt controller nodes
 -----------------------------
 
diff --git a/Documentation/devicetree/bindings/panel/auo,b116xw03.txt b/Documentation/devicetree/bindings/panel/auo,b116xw03.txt
new file mode 100644 (file)
index 0000000..690d0a5
--- /dev/null
@@ -0,0 +1,7 @@
+AU Optronics Corporation 11.6" HD (1366x768) color TFT-LCD panel
+
+Required properties:
+- compatible: should be "auo,b116xw03"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/hannstar,hsd070pww1.txt b/Documentation/devicetree/bindings/panel/hannstar,hsd070pww1.txt
new file mode 100644 (file)
index 0000000..7da1d5c
--- /dev/null
@@ -0,0 +1,7 @@
+HannStar Display Corp. HSD070PWW1 7.0" WXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "hannstar,hsd070pww1"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/hit,tx23d38vm0caa.txt b/Documentation/devicetree/bindings/panel/hit,tx23d38vm0caa.txt
new file mode 100644 (file)
index 0000000..04caaae
--- /dev/null
@@ -0,0 +1,7 @@
+Hitachi Ltd. Corporation 9" WVGA (800x480) TFT LCD panel
+
+Required properties:
+- compatible: should be "hit,tx23d38vm0caa"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/innolux,g121i1-l01.txt b/Documentation/devicetree/bindings/panel/innolux,g121i1-l01.txt
new file mode 100644 (file)
index 0000000..2743b07
--- /dev/null
@@ -0,0 +1,7 @@
+Innolux Corporation 12.1" WXGA (1280x800) TFT LCD panel
+
+Required properties:
+- compatible: should be "innolux,g121i1-l01"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/sharp,lq101r1sx01.txt b/Documentation/devicetree/bindings/panel/sharp,lq101r1sx01.txt
new file mode 100644 (file)
index 0000000..f522bb8
--- /dev/null
@@ -0,0 +1,49 @@
+Sharp Microelectronics 10.1" WQXGA TFT LCD panel
+
+This panel requires a dual-channel DSI host to operate. It supports two modes:
+- left-right: each channel drives the left or right half of the screen
+- even-odd: each channel drives the even or odd lines of the screen
+
+Each of the DSI channels controls a separate DSI peripheral. The peripheral
+driven by the first link (DSI-LINK1), left or even, is considered the primary
+peripheral and controls the device. The 'link2' property contains a phandle
+to the peripheral driven by the second link (DSI-LINK2, right or odd).
+
+Note that in video mode the DSI-LINK1 interface always provides the left/even
+pixels and DSI-LINK2 always provides the right/odd pixels. In command mode it
+is possible to program either link to drive the left/even or right/odd pixels
+but for the sake of consistency this binding assumes that the same assignment
+is chosen as for video mode.
+
+Required properties:
+- compatible: should be "sharp,lq101r1sx01"
+- reg: DSI virtual channel of the peripheral
+
+Required properties (for DSI-LINK1 only):
+- link2: phandle to the DSI peripheral on the secondary link. Note that the
+  presence of this property marks the containing node as DSI-LINK1.
+- power-supply: phandle of the regulator that provides the supply voltage
+
+Optional properties (for DSI-LINK1 only):
+- backlight: phandle of the backlight device attached to the panel
+
+Example:
+
+       dsi@54300000 {
+               panel: panel@0 {
+                       compatible = "sharp,lq101r1sx01";
+                       reg = <0>;
+
+                       link2 = <&secondary>;
+
+                       power-supply = <...>;
+                       backlight = <...>;
+               };
+       };
+
+       dsi@54400000 {
+               secondary: panel@0 {
+                       compatible = "sharp,lq101r1sx01";
+                       reg = <0>;
+               };
+       };
index 41aeed38926d19e84b67f3194994ded9c584106c..f8fbe9af7b2f276350426b299c6030adb9464640 100644 (file)
@@ -7,3 +7,14 @@ And for the interrupt mapping part:
 
 Open Firmware Recommended Practice: Interrupt Mapping
 http://www.openfirmware.org/1275/practice/imap/imap0_9d.pdf
+
+Additionally to the properties specified in the above standards a host bridge
+driver implementation may support the following properties:
+
+- linux,pci-domain:
+   If present this property assigns a fixed PCI domain number to a host bridge,
+   otherwise an unstable (across boots) unique number will be assigned.
+   It is required to either not set this property at all or set it for all
+   host bridges in the system, otherwise potentially conflicting domain numbers
+   may be assigned to root buses behind different host bridges.  The domain
+   number for each host bridge in the system must be unique.
index a186181c402ba693b43c71e5f129e6cb05cfcde7..51b943cc9770e1b096e3def62c3e902c4ce02772 100644 (file)
@@ -9,7 +9,7 @@ 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".
 
-TZ1090-PDC's pin configuration nodes act as a container for an abitrary number
+TZ1090-PDC's 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
index 4b27c99f7f9d496028ae215b7c79d3cc4b1e995b..49d0e6050940256edde1dd8a2dcc2a84c6b5f910 100644 (file)
@@ -9,7 +9,7 @@ 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".
 
-TZ1090's pin configuration nodes act as a container for an abitrary number of
+TZ1090's 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
index daa7689560695d1769bdf7d2064ff1f0181873d6..ac4da9fe07bd1fe28d2ceabacbca5453ff41e7a5 100644 (file)
@@ -9,7 +9,7 @@ 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".
 
-Lantiq's pin configuration nodes act as a container for an abitrary number of
+Lantiq's 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 group(s), and two pin configuration parameters:
index b5469db1d7adc2d4f2ff36adf6ed75e2802fe116..e89b4677567d0fcd9a4550905ea806d905d951c0 100644 (file)
@@ -9,7 +9,7 @@ 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".
 
-Lantiq's pin configuration nodes act as a container for an abitrary number of
+Lantiq's 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 group(s), and two pin configuration parameters:
index 61e73cde9ae9437303b7b095dc2d14c1d4966f62..3c8ce28baad63b164513875221a298dca5bb2066 100644 (file)
@@ -9,7 +9,7 @@ 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".
 
-Tegra's pin configuration nodes act as a container for an abitrary number of
+Tegra's 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
index c596a6ad3285acdd52d357a6e4a56cee98a7eb56..5f55be59d914a33aa71f4f432237782fd45f46ad 100644 (file)
@@ -13,7 +13,7 @@ Optional properties:
 Please refer to pinctrl-bindings.txt in this directory for details of the common
 pinctrl bindings used by client devices.
 
-SiRFprimaII's pinmux nodes act as a container for an abitrary number of subnodes.
+SiRFprimaII's pinmux nodes act as a container for an arbitrary number of subnodes.
 Each of these subnodes represents some desired configuration for a group of pins.
 
 Required subnode-properties:
index b4480d5c3aca93a99721829c604c5a823c28bc82..458615596946f6d29ccd60401f87a419fbe0e84a 100644 (file)
@@ -32,7 +32,7 @@ Required properties:
 Please refer to pinctrl-bindings.txt in this directory for details of the common
 pinctrl bindings used by client devices.
 
-SPEAr's pinmux nodes act as a container for an abitrary number of subnodes. Each
+SPEAr's pinmux nodes act as a container for an arbitrary number of subnodes. Each
 of these subnodes represents muxing for a pin, a group, or a list of pins or
 groups.
 
index 2fb90b37aa09080fec5dc37caaafd72d73548607..a7bde64798c7e33a7a84e73bb92f82d5d7fd53eb 100644 (file)
@@ -18,7 +18,7 @@ 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".
 
-Qualcomm's pin configuration nodes act as a container for an abitrary number of
+Qualcomm's 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
index ffafa1990a3048baaf36efce244e4c9ea4e7887f..c4ea61ac56f2fdbdd535a6123ba29c3a05acfb01 100644 (file)
@@ -47,7 +47,7 @@ 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 abitrary number of
+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
index e33e4dcdce79bdfb51e17b4ab1bbb5602db569b0..6e88e91feb1130796dacf610ceb0a6969c5b0b95 100644 (file)
@@ -18,7 +18,7 @@ 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".
 
-Qualcomm's pin configuration nodes act as a container for an abitrary number of
+Qualcomm's 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
index 93b7de91b9f6f62d824436c003ee332705a1efdb..eb8d8aa41f2051a8be7c87e4d10c12b68f6a76d8 100644 (file)
@@ -47,7 +47,7 @@ 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 abitrary number of
+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
index d2ea80dc43ebca126558ed3f97d8a395f1b63c7c..e4d6a9d20f7d0d82c684356f03397f95872ffe26 100644 (file)
@@ -18,7 +18,7 @@ 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".
 
-Qualcomm's pin configuration nodes act as a container for an abitrary number of
+Qualcomm's 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
diff --git a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
deleted file mode 100644 (file)
index e75f0e5..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-Freescale i.MX DRM master device
-================================
-
-The freescale i.MX DRM master device is a virtual device needed to list all
-IPU or other display interface nodes that comprise the graphics subsystem.
-
-Required properties:
-- compatible: Should be "fsl,imx-display-subsystem"
-- ports: Should contain a list of phandles pointing to display interface ports
-  of IPU devices
-
-example:
-
-display-subsystem {
-       compatible = "fsl,display-subsystem";
-       ports = <&ipu_di0>;
-};
-
-
-Freescale i.MX IPUv3
-====================
-
-Required properties:
-- compatible: Should be "fsl,<chip>-ipu"
-- reg: should be register base and length as documented in the
-  datasheet
-- interrupts: Should contain sync interrupt and error interrupt,
-  in this order.
-- resets: phandle pointing to the system reset controller and
-          reset line index, see reset/fsl,imx-src.txt for details
-Optional properties:
-- port@[0-3]: Port nodes with endpoint definitions as defined in
-  Documentation/devicetree/bindings/media/video-interfaces.txt.
-  Ports 0 and 1 should correspond to CSI0 and CSI1,
-  ports 2 and 3 should correspond to DI0 and DI1, respectively.
-
-example:
-
-ipu: ipu@18000000 {
-       #address-cells = <1>;
-       #size-cells = <0>;
-       compatible = "fsl,imx53-ipu";
-       reg = <0x18000000 0x080000000>;
-       interrupts = <11 10>;
-       resets = <&src 2>;
-
-       ipu_di0: port@2 {
-               reg = <2>;
-
-               ipu_di0_disp0: endpoint {
-                       remote-endpoint = <&display_in>;
-               };
-       };
-};
-
-Parallel display support
-========================
-
-Required properties:
-- compatible: Should be "fsl,imx-parallel-display"
-Optional properties:
-- interface_pix_fmt: How this display is connected to the
-  display interface. Currently supported types: "rgb24", "rgb565", "bgr666"
-  and "lvds666".
-- edid: verbatim EDID data block describing attached display.
-- ddc: phandle describing the i2c bus handling the display data
-  channel
-- port: A port node with endpoint definitions as defined in
-  Documentation/devicetree/bindings/media/video-interfaces.txt.
-
-example:
-
-display@di0 {
-       compatible = "fsl,imx-parallel-display";
-       edid = [edid-data];
-       interface-pix-fmt = "rgb24";
-
-       port {
-               display_in: endpoint {
-                       remote-endpoint = <&ipu_di0_disp0>;
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt b/Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt
deleted file mode 100644 (file)
index 1b756cf..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-Device-Tree bindings for HDMI Transmitter
-
-HDMI Transmitter
-================
-
-The HDMI Transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
-with accompanying PHY IP.
-
-Required properties:
- - #address-cells : should be <1>
- - #size-cells : should be <0>
- - compatible : should be "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi".
- - gpr : should be <&gpr>.
-   The phandle points to the iomuxc-gpr region containing the HDMI
-   multiplexer control register.
- - clocks, clock-names : phandles to the HDMI iahb and isrf clocks, as described
-   in Documentation/devicetree/bindings/clock/clock-bindings.txt and
-   Documentation/devicetree/bindings/clock/imx6q-clock.txt.
- - port@[0-4]: Up to four port nodes with endpoint definitions as defined in
-   Documentation/devicetree/bindings/media/video-interfaces.txt,
-   corresponding to the four inputs to the HDMI multiplexer.
-
-Optional properties:
- - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
-
-example:
-
-       gpr: iomuxc-gpr@020e0000 {
-               /* ... */
-       };
-
-        hdmi: hdmi@0120000 {
-                #address-cells = <1>;
-                #size-cells = <0>;
-                compatible = "fsl,imx6q-hdmi";
-                reg = <0x00120000 0x9000>;
-                interrupts = <0 115 0x04>;
-                gpr = <&gpr>;
-                clocks = <&clks 123>, <&clks 124>;
-                clock-names = "iahb", "isfr";
-                ddc-i2c-bus = <&i2c2>;
-
-                port@0 {
-                        reg = <0>;
-
-                        hdmi_mux_0: endpoint {
-                                remote-endpoint = <&ipu1_di0_hdmi>;
-                        };
-                };
-
-                port@1 {
-                        reg = <1>;
-
-                        hdmi_mux_1: endpoint {
-                                remote-endpoint = <&ipu1_di1_hdmi>;
-                        };
-                };
-        };
diff --git a/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt b/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt
deleted file mode 100644 (file)
index 443bcb6..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-Device-Tree bindings for LVDS Display Bridge (ldb)
-
-LVDS Display Bridge
-===================
-
-The LVDS Display Bridge device tree node contains up to two lvds-channel
-nodes describing each of the two LVDS encoder channels of the bridge.
-
-Required properties:
- - #address-cells : should be <1>
- - #size-cells : should be <0>
- - compatible : should be "fsl,imx53-ldb" or "fsl,imx6q-ldb".
-                Both LDB versions are similar, but i.MX6 has an additional
-                multiplexer in the front to select any of the four IPU display
-                interfaces as input for each LVDS channel.
- - gpr : should be <&gpr> on i.MX53 and i.MX6q.
-         The phandle points to the iomuxc-gpr region containing the LVDS
-         control register.
-- clocks, clock-names : phandles to the LDB divider and selector clocks and to
-                        the display interface selector clocks, as described in
-                        Documentation/devicetree/bindings/clock/clock-bindings.txt
-        The following clocks are expected on i.MX53:
-                "di0_pll" - LDB LVDS channel 0 mux
-                "di1_pll" - LDB LVDS channel 1 mux
-                "di0" - LDB LVDS channel 0 gate
-                "di1" - LDB LVDS channel 1 gate
-                "di0_sel" - IPU1 DI0 mux
-                "di1_sel" - IPU1 DI1 mux
-        On i.MX6q the following additional clocks are needed:
-                "di2_sel" - IPU2 DI0 mux
-                "di3_sel" - IPU2 DI1 mux
-        The needed clock numbers for each are documented in
-        Documentation/devicetree/bindings/clock/imx5-clock.txt, and in
-        Documentation/devicetree/bindings/clock/imx6q-clock.txt.
-
-Optional properties:
- - pinctrl-names : should be "default" on i.MX53, not used on i.MX6q
- - pinctrl-0 : a phandle pointing to LVDS pin settings on i.MX53,
-               not used on i.MX6q
- - fsl,dual-channel : boolean. if it exists, only LVDS channel 0 should
-   be configured - one input will be distributed on both outputs in dual
-   channel mode
-
-LVDS Channel
-============
-
-Each LVDS Channel has to contain a display-timings node that describes the
-video timings for the connected LVDS display. For detailed information, also
-have a look at Documentation/devicetree/bindings/video/display-timing.txt.
-
-Required properties:
- - reg : should be <0> or <1>
- - fsl,data-mapping : should be "spwg" or "jeida"
-                      This describes how the color bits are laid out in the
-                      serialized LVDS signal.
- - fsl,data-width : should be <18> or <24>
- - port: A port node with endpoint definitions as defined in
-   Documentation/devicetree/bindings/media/video-interfaces.txt.
-   On i.MX5, the internal two-input-multiplexer is used.
-   Due to hardware limitations, only one port (port@[0,1])
-   can be used for each channel (lvds-channel@[0,1], respectively)
-   On i.MX6, there should be four ports (port@[0-3]) that correspond
-   to the four LVDS multiplexer inputs.
-
-example:
-
-gpr: iomuxc-gpr@53fa8000 {
-       /* ... */
-};
-
-ldb: ldb@53fa8008 {
-       #address-cells = <1>;
-       #size-cells = <0>;
-       compatible = "fsl,imx53-ldb";
-       gpr = <&gpr>;
-       clocks = <&clks 122>, <&clks 120>,
-                <&clks 115>, <&clks 116>,
-                <&clks 123>, <&clks 85>;
-       clock-names = "di0_pll", "di1_pll",
-                     "di0_sel", "di1_sel",
-                     "di0", "di1";
-
-       lvds-channel@0 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               reg = <0>;
-               fsl,data-mapping = "spwg";
-               fsl,data-width = <24>;
-
-               display-timings {
-                       /* ... */
-               };
-
-               port@0 {
-                       reg = <0>;
-
-                       lvds0_in: endpoint {
-                               remote-endpoint = <&ipu_di0_lvds0>;
-                       };
-               };
-       };
-
-       lvds-channel@1 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               reg = <1>;
-               fsl,data-mapping = "spwg";
-               fsl,data-width = <24>;
-
-               display-timings {
-                       /* ... */
-               };
-
-               port@1 {
-                       reg = <1>;
-
-                       lvds1_in: endpoint {
-                               remote-endpoint = <&ipu_di1_lvds1>;
-                       };
-               };
-       };
-};
index 723999d737445274728bedde163d3534ca62339c..78efebbf278808b88f23f06c0be73bee1e00ee55 100644 (file)
@@ -34,6 +34,7 @@ chipidea      Chipidea, Inc
 chrp   Common Hardware Reference Platform
 chunghwa       Chunghwa Picture Tubes Ltd.
 cirrus Cirrus Logic, Inc.
+cnm    Chips&Media, Inc.
 cortina        Cortina Systems, Inc.
 crystalfontz   Crystalfontz America, Inc.
 dallas Maxim Integrated Products (formerly Dallas Semiconductor)
@@ -64,8 +65,10 @@ gmt  Global Mixed-mode Technology, Inc.
 google Google, Inc.
 gumstix        Gumstix, Inc.
 gw     Gateworks Corporation
+hannstar       HannStar Display Corporation
 haoyu  Haoyu Microelectronic Co. Ltd.
 hisilicon      Hisilicon Limited.
+hit    Hitachi Ltd.
 honeywell      Honeywell
 hp     Hewlett Packard
 i2se   I2SE GmbH
@@ -92,6 +95,7 @@ maxim Maxim Integrated Products
 mediatek       MediaTek Inc.
 micrel Micrel Inc.
 microchip      Microchip Technology Inc.
+micron Micron Technology Inc.
 mitsubishi     Mitsubishi Electric Corporation
 mosaixtech     Mosaix Technologies, Inc.
 moxa   Moxa
@@ -127,6 +131,7 @@ renesas     Renesas Electronics Corporation
 ricoh  Ricoh Co. Ltd.
 rockchip       Fuzhou Rockchip Electronics Co., Ltd
 samsung        Samsung Semiconductor
+sandisk        Sandisk Corporation
 sbs    Smart Battery System
 schindler      Schindler
 seagate        Seagate Technology PLC
@@ -138,7 +143,7 @@ silergy     Silergy Corp.
 sirf   SiRF Technology, Inc.
 sitronix       Sitronix Technology Corporation
 smsc   Standard Microsystems Corporation
-snps   Synopsys, Inc.
+snps   Synopsys, Inc.
 solidrun       SolidRun
 sony   Sony Corporation
 spansion       Spansion Inc.
diff --git a/Documentation/devicetree/bindings/video/adi,adv7511.txt b/Documentation/devicetree/bindings/video/adi,adv7511.txt
new file mode 100644 (file)
index 0000000..96c25ee
--- /dev/null
@@ -0,0 +1,88 @@
+Analog Device ADV7511(W)/13 HDMI Encoders
+-----------------------------------------
+
+The ADV7511, ADV7511W and ADV7513 are HDMI audio and video transmitters
+compatible with HDMI 1.4 and DVI 1.0. They support color space conversion,
+S/PDIF, CEC and HDCP.
+
+Required properties:
+
+- compatible: Should be one of "adi,adv7511", "adi,adv7511w" or "adi,adv7513"
+- reg: I2C slave address
+
+The ADV7511 supports a large number of input data formats that differ by their
+color depth, color format, clock mode, bit justification and random
+arrangement of components on the data bus. The combination of the following
+properties describe the input and map directly to the video input tables of the
+ADV7511 datasheet that document all the supported combinations.
+
+- adi,input-depth: Number of bits per color component at the input (8, 10 or
+  12).
+- adi,input-colorspace: The input color space, one of "rgb", "yuv422" or
+  "yuv444".
+- adi,input-clock: The input clock type, one of "1x" (one clock cycle per
+  pixel), "2x" (two clock cycles per pixel), "ddr" (one clock cycle per pixel,
+  data driven on both edges).
+
+The following input format properties are required except in "rgb 1x" and
+"yuv444 1x" modes, in which case they must not be specified.
+
+- adi,input-style: The input components arrangement variant (1, 2 or 3), as
+  listed in the input format tables in the datasheet.
+- adi,input-justification: The input bit justification ("left", "evenly",
+  "right").
+
+Optional properties:
+
+- interrupts: Specifier for the ADV7511 interrupt
+- pd-gpios: Specifier for the GPIO connected to the power down signal
+
+- adi,clock-delay: Video data clock delay relative to the pixel clock, in ps
+  (-1200 ps .. 1600 ps). Defaults to no delay.
+- adi,embedded-sync: The input uses synchronization signals embedded in the
+  data stream (similar to BT.656). Defaults to separate H/V synchronization
+  signals.
+
+Required nodes:
+
+The ADV7511 has two video ports. Their connections are modelled using the OF
+graph bindings specified in Documentation/devicetree/bindings/graph.txt.
+
+- Video port 0 for the RGB or YUV input
+- Video port 1 for the HDMI output
+
+
+Example
+-------
+
+       adv7511w: hdmi@39 {
+               compatible = "adi,adv7511w";
+               reg = <39>;
+               interrupt-parent = <&gpio3>;
+               interrupts = <29 IRQ_TYPE_EDGE_FALLING>;
+
+               adi,input-depth = <8>;
+               adi,input-colorspace = "rgb";
+               adi,input-clock = "1x";
+               adi,input-style = <1>;
+               adi,input-justification = "evenly";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               adv7511w_in: endpoint {
+                                       remote-endpoint = <&dpi_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+                               adv7511_out: endpoint {
+                                       remote-endpoint = <&hdmi_connector_in>;
+                               };
+                       };
+               };
+       };
index e74243b4b317ff74728c50b09e66b5f9347f6d69..ca2b4aacd9afb5e81d508df0371b4eb5b7f4f9b0 100644 (file)
@@ -4,6 +4,7 @@ Required properties:
   - compatible: value should be one of the following
                "samsung,exynos3250-mipi-dsi" /* for Exynos3250/3472 SoCs */
                "samsung,exynos4210-mipi-dsi" /* for Exynos4 SoCs */
+               "samsung,exynos4415-mipi-dsi" /* for Exynos4415 SoC */
                "samsung,exynos5410-mipi-dsi" /* for Exynos5410/5420/5440 SoCs */
   - reg: physical base address and length of the registers set for the device
   - interrupts: should contain DSI interrupt
index 4e6c77c85546790bbb8b85c6528e31287ac9e81a..cf1af637102169a0c2b8059e4440132fce0d6bb2 100644 (file)
@@ -11,6 +11,7 @@ Required properties:
                "samsung,s5pv210-fimd"; /* for S5PV210 SoC */
                "samsung,exynos3250-fimd"; /* for Exynos3250/3472 SoCs */
                "samsung,exynos4210-fimd"; /* for Exynos4 SoCs */
+               "samsung,exynos4415-fimd"; /* for Exynos4415 SoC */
                "samsung,exynos5250-fimd"; /* for Exynos5 SoCs */
 
 - reg: physical base address and length of the FIMD registers set.
index 530850a72735ac6c47c46a51e71b84ca427cee5d..a27c950ece61b0d312fbba2a3757fab71c5b3616 100644 (file)
@@ -64,7 +64,7 @@ is formed.
 At mount time, the two directories given as mount options "lowerdir" and
 "upperdir" are combined into a merged directory:
 
-  mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper,\
+  mount -t overlay overlay -olowerdir=/lower,upperdir=/upper,\
 workdir=/work /merged
 
 The "workdir" needs to be an empty directory on the same filesystem
index 412f45ca2d73e3cd31a487e5fe13b73fc552d9f5..1d6d02d6ba52b531642436e8a6d8c0640af5467d 100644 (file)
@@ -136,7 +136,7 @@ SOF_TIMESTAMPING_OPT_ID:
 
   This option is implemented only for transmit timestamps. There, the
   timestamp is always looped along with a struct sock_extended_err.
-  The option modifies field ee_info to pass an id that is unique
+  The option modifies field ee_data to pass an id that is unique
   among all possibly concurrently outstanding timestamp requests for
   that socket. In practice, it is a monotonically increasing u32
   (that wraps).
index c444907ccd69edf8d18ef523c74f758db52a6831..55d3e9b93338b38a05668dff834c33c8fa8428e8 100644 (file)
@@ -618,6 +618,16 @@ S: Maintained
 F:     drivers/iommu/amd_iommu*.[ch]
 F:     include/linux/amd-iommu.h
 
+AMD KFD
+M:      Oded Gabbay <oded.gabbay@amd.com>
+L:      dri-devel@lists.freedesktop.org
+T:      git git://people.freedesktop.org/~gabbayo/linux.git
+S:      Supported
+F:      drivers/gpu/drm/amd/amdkfd/
+F:      drivers/gpu/drm/radeon/radeon_kfd.c
+F:      drivers/gpu/drm/radeon/radeon_kfd.h
+F:      include/uapi/linux/kfd_ioctl.h
+
 AMD MICROCODE UPDATE SUPPORT
 M:     Andreas Herrmann <herrmann.der.user@googlemail.com>
 L:     amd64-microcode@amd64.org
@@ -3206,6 +3216,13 @@ F:       drivers/gpu/drm/exynos/
 F:     include/drm/exynos*
 F:     include/uapi/drm/exynos*
 
+DRM DRIVERS FOR FREESCALE IMX
+M:     Philipp Zabel <p.zabel@pengutronix.de>
+L:     dri-devel@lists.freedesktop.org
+S:     Maintained
+F:     drivers/gpu/drm/imx/
+F:     Documentation/devicetree/bindings/drm/imx/
+
 DRM DRIVERS FOR NVIDIA TEGRA
 M:     Thierry Reding <thierry.reding@gmail.com>
 M:     Terje Bergström <tbergstrom@nvidia.com>
@@ -6888,11 +6905,12 @@ F:      drivers/scsi/osd/
 F:     include/scsi/osd_*
 F:     fs/exofs/
 
-OVERLAYFS FILESYSTEM
+OVERLAY FILESYSTEM
 M:     Miklos Szeredi <miklos@szeredi.hu>
-L:     linux-fsdevel@vger.kernel.org
+L:     linux-unionfs@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git
 S:     Supported
-F:     fs/overlayfs/*
+F:     fs/overlayfs/
 F:     Documentation/filesystems/overlayfs.txt
 
 P54 WIRELESS DRIVER
index 00d618bbe8e7588a8c36ed0ba0371b219e8d8543..ce70361f766e783d43cc9b6dab00d1cd34304a6f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 18
 SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION = -rc7
 NAME = Diseased Newt
 
 # *DOCUMENTATION*
index e51fcef884a43d629ab12132e549cc8a0b731405..60429ad1c5d8451c1e481e0190ad5d312dc54522 100644 (file)
        num-cs = <1>;
 };
 
+&usbdrd_dwc3 {
+       dr_mode = "host";
+};
+
 #include "cros-ec-keyboard.dtsi"
index f21b9aa00fbb214f4dee8b0b1980884f5411c70f..d55c1a2eb798966340325afbb5c3009c8bcef28c 100644 (file)
                #size-cells = <1>;
                ranges;
 
-               dwc3 {
+               usbdrd_dwc3: dwc3 {
                        compatible = "synopsys,dwc3";
                        reg = <0x12000000 0x10000>;
                        interrupts = <0 72 0>;
index d46c213a17ad5de43972fd4f7b28beda61b53347..eed697a6bd6bb290ca16f2536cf04651d56c2d15 100644 (file)
                        clocks = <&cpg_clocks R8A7740_CLK_S>,
                                 <&cpg_clocks R8A7740_CLK_S>, <&sub_clk>,
                                 <&cpg_clocks R8A7740_CLK_B>,
-                                <&sub_clk>, <&sub_clk>,
+                                <&cpg_clocks R8A7740_CLK_HPP>, <&sub_clk>,
                                 <&cpg_clocks R8A7740_CLK_B>;
                        #clock-cells = <1>;
                        renesas,clock-indices = <
index c160404e4d405eb2acedc5affd96781ee8bca162..765978fe430bd32b185a7f727b4edf34cd322ba2 100644 (file)
                        gpios = <&gpio4 31 GPIO_ACTIVE_HIGH>;
                };
        };
+
+       vga-encoder {
+               compatible = "adi,adv7123";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               vga_enc_in: endpoint {
+                                       remote-endpoint = <&du_out_rgb0>;
+                               };
+                       };
+                       port@1 {
+                               reg = <1>;
+                               vga_enc_out: endpoint {
+                                       remote-endpoint = <&vga_in>;
+                               };
+                       };
+               };
+       };
+
+       vga {
+               compatible = "vga-connector";
+
+               port {
+                       vga_in: endpoint {
+                               remote-endpoint = <&vga_enc_out>;
+                       };
+               };
+       };
+
+       lvds-encoder {
+               compatible = "thine,thc63lvdm83d";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               lvds_enc_in: endpoint {
+                                       remote-endpoint = <&du_out_rgb1>;
+                               };
+                       };
+                       port@1 {
+                               reg = <1>;
+                               lvds_connector: endpoint {
+                               };
+                       };
+               };
+       };
+};
+
+&du {
+       pinctrl-0 = <&du_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+
+       ports {
+               port@0 {
+                       endpoint {
+                               remote-endpoint = <&vga_enc_in>;
+                       };
+               };
+               port@1 {
+                       endpoint {
+                               remote-endpoint = <&lvds_enc_in>;
+                       };
+               };
+       };
 };
 
 &irqpin0 {
 };
 
 &pfc {
+       du_pins: du {
+               du0 {
+                       renesas,groups = "du0_rgb888", "du0_sync_1", "du0_clk_out_0";
+                       renesas,function = "du0";
+               };
+               du1 {
+                       renesas,groups = "du1_rgb666", "du1_sync_1", "du1_clk_out";
+                       renesas,function = "du1";
+               };
+       };
+
        lan0_pins: lan0 {
                intc {
                        renesas,groups = "intc_irq1_b";
index 7cfba9aa1b415cc180dae8f0a75901fb5921f488..fda814ed191d1531502480f308cc481e18ffad37 100644 (file)
                status = "disabled";
        };
 
+       du: display@fff80000 {
+               compatible = "renesas,du-r8a7779";
+               reg = <0 0xfff80000 0 0x40000>;
+               interrupts = <0 31 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp1_clks R8A7779_CLK_DU>;
+               status = "disabled";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               du_out_rgb0: endpoint {
+                               };
+                       };
+                       port@1 {
+                               reg = <1>;
+                               du_out_rgb1: endpoint {
+                               };
+                       };
+               };
+       };
+
        clocks {
                #address-cells = <1>;
                #size-cells = <1>;
index 69098b906b3919d2653dd244b6cc3220d6dfb741..5237d463ae1d59d2defb8a9460abb06b33905db0 100644 (file)
                states = <3300000 1
                          1800000 0>;
        };
+
+       vga-encoder {
+               compatible = "adi,adv7123";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               adv7123_in: endpoint {
+                                       remote-endpoint = <&du_out_rgb>;
+                               };
+                       };
+                       port@1 {
+                               reg = <1>;
+                               adv7123_out: endpoint {
+                                       remote-endpoint = <&vga_in>;
+                               };
+                       };
+               };
+       };
+
+       vga {
+               compatible = "vga-connector";
+
+               port {
+                       vga_in: endpoint {
+                               remote-endpoint = <&adv7123_out>;
+                       };
+               };
+       };
+};
+
+&du {
+       pinctrl-0 = <&du_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+
+       ports {
+               port@0 {
+                       endpoint {
+                               remote-endpoint = <&adv7123_in>;
+                       };
+               };
+               port@2 {
+                       lvds_connector: endpoint {
+                       };
+               };
+       };
 };
 
 &extal_clk {
 };
 
 &pfc {
-       pinctrl-0 = <&du_pins>;
-       pinctrl-names = "default";
-
        du_pins: du {
                renesas,groups = "du_rgb666", "du_sync_1", "du_clk_out_0";
                renesas,function = "du";
index d0e17733dc1a340608b10b3f4f595e93ec53d45d..0c20c90d8c0613f56207bcc421cf4c74c076c367 100644 (file)
                status = "disabled";
        };
 
+       vsp1@fe920000 {
+               compatible = "renesas,vsp1";
+               reg = <0 0xfe920000 0 0x8000>;
+               interrupts = <0 266 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp1_clks R8A7790_CLK_VSP1_R>;
+
+               renesas,has-sru;
+               renesas,#rpf = <5>;
+               renesas,#uds = <1>;
+               renesas,#wpf = <4>;
+       };
+
+       vsp1@fe928000 {
+               compatible = "renesas,vsp1";
+               reg = <0 0xfe928000 0 0x8000>;
+               interrupts = <0 267 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp1_clks R8A7790_CLK_VSP1_S>;
+
+               renesas,has-lut;
+               renesas,has-sru;
+               renesas,#rpf = <5>;
+               renesas,#uds = <3>;
+               renesas,#wpf = <4>;
+       };
+
+       vsp1@fe930000 {
+               compatible = "renesas,vsp1";
+               reg = <0 0xfe930000 0 0x8000>;
+               interrupts = <0 246 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp1_clks R8A7790_CLK_VSP1_DU0>;
+
+               renesas,has-lif;
+               renesas,has-lut;
+               renesas,#rpf = <4>;
+               renesas,#uds = <1>;
+               renesas,#wpf = <4>;
+       };
+
+       vsp1@fe938000 {
+               compatible = "renesas,vsp1";
+               reg = <0 0xfe938000 0 0x8000>;
+               interrupts = <0 247 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp1_clks R8A7790_CLK_VSP1_DU1>;
+
+               renesas,has-lif;
+               renesas,has-lut;
+               renesas,#rpf = <4>;
+               renesas,#uds = <1>;
+               renesas,#wpf = <4>;
+       };
+
+       du: display@feb00000 {
+               compatible = "renesas,du-r8a7790";
+               reg = <0 0xfeb00000 0 0x70000>,
+                     <0 0xfeb90000 0 0x1c>,
+                     <0 0xfeb94000 0 0x1c>;
+               reg-names = "du", "lvds.0", "lvds.1";
+               interrupts = <0 256 IRQ_TYPE_LEVEL_HIGH>,
+                            <0 268 IRQ_TYPE_LEVEL_HIGH>,
+                            <0 269 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp7_clks R8A7790_CLK_DU0>,
+                        <&mstp7_clks R8A7790_CLK_DU1>,
+                        <&mstp7_clks R8A7790_CLK_DU2>,
+                        <&mstp7_clks R8A7790_CLK_LVDS0>,
+                        <&mstp7_clks R8A7790_CLK_LVDS1>;
+               clock-names = "du.0", "du.1", "du.2", "lvds.0", "lvds.1";
+               status = "disabled";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               du_out_rgb: endpoint {
+                               };
+                       };
+                       port@1 {
+                               reg = <1>;
+                               du_out_lvds0: endpoint {
+                               };
+                       };
+                       port@2 {
+                               reg = <2>;
+                               du_out_lvds1: endpoint {
+                               };
+                       };
+               };
+       };
+
        clocks {
                #address-cells = <2>;
                #size-cells = <2>;
                        #clock-cells = <0>;
                        clock-output-names = "sd2";
                };
-               sd3_clk: sd3_clk@e615007c {
+               sd3_clk: sd3_clk@e615026c {
                        compatible = "renesas,r8a7790-div6-clock", "renesas,cpg-div6-clock";
-                       reg = <0 0xe615007c 0 4>;
+                       reg = <0 0xe615026c 0 4>;
                        clocks = <&pll1_div2_clk>;
                        #clock-cells = <0>;
                        clock-output-names = "sd3";
index 07550e775e8047111e2f280ef8d94da993970ebb..4f4e56e5de3de4a12228f07dd7d467a0a9603888 100644 (file)
        };
 };
 
+&du {
+       pinctrl-0 = <&du_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+
+       ports {
+               port@1 {
+                       lvds_connector: endpoint {
+                       };
+               };
+       };
+};
+
 &extal_clk {
        clock-frequency = <20000000>;
 };
 
 &pfc {
-       pinctrl-0 = <&du_pins>;
-       pinctrl-names = "default";
-
        i2c2_pins: i2c2 {
                renesas,groups = "i2c2";
                renesas,function = "i2c2";
index e06c11fa8698cfcc4cd5fc13ce1f905f554de01f..e4a7170f368b6cd6e66c62219f1d675d99b0ac30 100644 (file)
                status = "disabled";
        };
 
+       vsp1@fe928000 {
+               compatible = "renesas,vsp1";
+               reg = <0 0xfe928000 0 0x8000>;
+               interrupts = <0 267 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp1_clks R8A7791_CLK_VSP1_S>;
+
+               renesas,has-lut;
+               renesas,has-sru;
+               renesas,#rpf = <5>;
+               renesas,#uds = <3>;
+               renesas,#wpf = <4>;
+       };
+
+       vsp1@fe930000 {
+               compatible = "renesas,vsp1";
+               reg = <0 0xfe930000 0 0x8000>;
+               interrupts = <0 246 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp1_clks R8A7791_CLK_VSP1_DU0>;
+
+               renesas,has-lif;
+               renesas,has-lut;
+               renesas,#rpf = <4>;
+               renesas,#uds = <1>;
+               renesas,#wpf = <4>;
+       };
+
+       vsp1@fe938000 {
+               compatible = "renesas,vsp1";
+               reg = <0 0xfe938000 0 0x8000>;
+               interrupts = <0 247 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp1_clks R8A7791_CLK_VSP1_DU1>;
+
+               renesas,has-lif;
+               renesas,has-lut;
+               renesas,#rpf = <4>;
+               renesas,#uds = <1>;
+               renesas,#wpf = <4>;
+       };
+
+       du: display@feb00000 {
+               compatible = "renesas,du-r8a7791";
+               reg = <0 0xfeb00000 0 0x40000>,
+                     <0 0xfeb90000 0 0x1c>;
+               reg-names = "du", "lvds.0";
+               interrupts = <0 256 IRQ_TYPE_LEVEL_HIGH>,
+                            <0 268 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp7_clks R8A7791_CLK_DU0>,
+                        <&mstp7_clks R8A7791_CLK_DU1>,
+                        <&mstp7_clks R8A7791_CLK_LVDS0>;
+               clock-names = "du.0", "du.1", "lvds.0";
+               status = "disabled";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+                               du_out_rgb: endpoint {
+                               };
+                       };
+                       port@1 {
+                               reg = <1>;
+                               du_out_lvds0: endpoint {
+                               };
+                       };
+               };
+       };
+
        clocks {
                #address-cells = <2>;
                #size-cells = <2>;
diff --git a/arch/arm/boot/dts/r8a77xx-aa104xd12-panel.dtsi b/arch/arm/boot/dts/r8a77xx-aa104xd12-panel.dtsi
new file mode 100644 (file)
index 0000000..65cb50f
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Common file for the AA104XD12 panel connected to Renesas R-Car boards
+ *
+ * Copyright (C) 2014 Renesas Electronics Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/ {
+       panel {
+               compatible = "mitsubishi,aa104xd12", "panel-dpi";
+
+               width-mm = <210>;
+               height-mm = <158>;
+
+               panel-timing {
+                       /* 1024x768 @65Hz */
+                       clock-frequency = <65000000>;
+                       hactive = <1024>;
+                       vactive = <768>;
+                       hsync-len = <136>;
+                       hfront-porch = <20>;
+                       hback-porch = <160>;
+                       vfront-porch = <3>;
+                       vback-porch = <29>;
+                       vsync-len = <6>;
+               };
+
+               port {
+                       panel_in: endpoint {
+                               remote-endpoint = <&lvds_connector>;
+                       };
+               };
+       };
+};
+
+&lvds_connector {
+       remote-endpoint = <&panel_in>;
+};
index 543f895d18d3c870446f52085095221566ef83a3..2e652e2339e9a1caf9c4abead9d7b958cc7515a1 100644 (file)
                        clocks = <&ahb1_gates 6>;
                        resets = <&ahb1_rst 6>;
                        #dma-cells = <1>;
+
+                       /* DMA controller requires AHB1 clocked from PLL6 */
+                       assigned-clocks = <&ahb1_mux>;
+                       assigned-clock-parents = <&pll6>;
                };
 
                mmc0: mmc@01c0f000 {
index 5c21d216515a3d5a06b76a4b449cc72ef208b6af..8b7aa0dcdc6ee4d4a04100650c1ac33cebcd6762 100644 (file)
@@ -15,6 +15,7 @@
        aliases {
                rtc0 = "/i2c@7000d000/tps65913@58";
                rtc1 = "/rtc@7000e000";
+               serial0 = &uartd;
        };
 
        memory {
index c7c6825f11fbb1b902b6f230eb62d8d8f88077a6..38acf78d7815fab2ab14842503a4bf79c040f9ed 100644 (file)
                linux,initrd-end = <0x82800000>;
        };
 
+       aliases {
+               serial0 = &uartd;
+       };
+
        firmware {
                trusted-foundations {
                        compatible = "tlm,trusted-foundations";
                                                regulator-name = "vddio-sdmmc3";
                                                regulator-min-microvolt = <1800000>;
                                                regulator-max-microvolt = <3300000>;
-                                               regulator-always-on;
-                                               regulator-boot-on;
                                        };
 
                                        ldousb {
        sdhci@78000400 {
                status = "okay";
                bus-width = <4>;
-               vmmc-supply = <&vddio_sdmmc3>;
+               vqmmc-supply = <&vddio_sdmmc3>;
                cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>;
                power-gpios = <&gpio TEGRA_GPIO(H, 0) GPIO_ACTIVE_HIGH>;
        };
        sdhci@78000600 {
                status = "okay";
                bus-width = <8>;
-               vmmc-supply = <&vdd_1v8>;
                non-removable;
        };
 
index 96366214563542479db657f80b12a28918e30824..f91c2c9b2f9431aef1e1611ba2eaf064a40aed7d 100644 (file)
                linux,initrd-end = <0x82800000>;
        };
 
+       aliases {
+               serial0 = &uartd;
+       };
+
        firmware {
                trusted-foundations {
                        compatible = "tlm,trusted-foundations";
        sdhci@78000600 {
                status = "okay";
                bus-width = <8>;
-               vmmc-supply = <&vdd_1v8>;
                non-removable;
        };
 
index 2ca9c1807f72374bb176aada1203f6d9bc88e220..222f3b3f4dd5c4f852259349228db76e89c7ac27 100644 (file)
@@ -9,13 +9,6 @@
        compatible = "nvidia,tegra114";
        interrupt-parent = <&gic>;
 
-       aliases {
-               serial0 = &uarta;
-               serial1 = &uartb;
-               serial2 = &uartc;
-               serial3 = &uartd;
-       };
-
        host1x@50000000 {
                compatible = "nvidia,tegra114-host1x", "simple-bus";
                reg = <0x50000000 0x00028000>;
index 029c9a0215413355d3ce7c081a3ac5bd00fcd3d7..51b373ff106555edf302c9066809ea4abbd25c5c 100644 (file)
@@ -10,6 +10,7 @@
        aliases {
                rtc0 = "/i2c@0,7000d000/pmic@40";
                rtc1 = "/rtc@0,7000e000";
+               serial0 = &uartd;
        };
 
        memory {
index 7d0784ce4c748183083fa4ab5947b9adfb083d72..53181d31024713796897f5980cf9994339eb691f 100644 (file)
@@ -10,6 +10,7 @@
        aliases {
                rtc0 = "/i2c@0,7000d000/pmic@40";
                rtc1 = "/rtc@0,7000e000";
+               serial0 = &uarta;
        };
 
        memory {
index 13008858e96754dda8de3f838add6e0b6d4fb911..5c3f7813360d2a59bffcc463f059b2047440fabf 100644 (file)
@@ -10,6 +10,7 @@
        aliases {
                rtc0 = "/i2c@0,7000d000/pmic@40";
                rtc1 = "/rtc@0,7000e000";
+               serial0 = &uarta;
        };
 
        memory {
index 478c555ebd96bd0897bae7d3d0e7fa368573cba5..df2b06b299851a85533243a96126e49e43813066 100644 (file)
         * the APB DMA based serial driver, the comptible is
         * "nvidia,tegra124-hsuart", "nvidia,tegra30-hsuart".
         */
-       serial@0,70006000 {
+       uarta: serial@0,70006000 {
                compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart";
                reg = <0x0 0x70006000 0x0 0x40>;
                reg-shift = <2>;
                status = "disabled";
        };
 
-       serial@0,70006040 {
+       uartb: serial@0,70006040 {
                compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart";
                reg = <0x0 0x70006040 0x0 0x40>;
                reg-shift = <2>;
                status = "disabled";
        };
 
-       serial@0,70006200 {
+       uartc: serial@0,70006200 {
                compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart";
                reg = <0x0 0x70006200 0x0 0x40>;
                reg-shift = <2>;
                status = "disabled";
        };
 
-       serial@0,70006300 {
+       uartd: serial@0,70006300 {
                compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart";
                reg = <0x0 0x70006300 0x0 0x40>;
                reg-shift = <2>;
index a37279af687c6a436ba5308c6139a5c3c8be9014..b926a07b944303fb24468d6899bc9324c7c956bb 100644 (file)
@@ -10,6 +10,7 @@
        aliases {
                rtc0 = "/i2c@7000d000/tps6586x@34";
                rtc1 = "/rtc@7000e000";
+               serial0 = &uartd;
        };
 
        memory {
index 8cfb83f42e1fd87ff608b171a2c404942975b0ff..1dd7d7bfdfcc25e3d3fcb35e6f17c4ccb95b2b5f 100644 (file)
@@ -6,6 +6,11 @@
        model = "Toradex Colibri T20 512MB on Iris";
        compatible = "toradex,iris", "toradex,colibri_t20-512", "nvidia,tegra20";
 
+       aliases {
+               serial0 = &uarta;
+               serial1 = &uartd;
+       };
+
        host1x@50000000 {
                hdmi@54280000 {
                        status = "okay";
index 1b7c56b33acae6f2c6c4b1da3154d6c92aebb96a..9b87526ab0b70fad25125a4f5764d418243aa50c 100644 (file)
@@ -6,6 +6,10 @@
        model = "Avionic Design Medcom-Wide board";
        compatible = "ad,medcom-wide", "ad,tamonten", "nvidia,tegra20";
 
+       aliases {
+               serial0 = &uartd;
+       };
+
        pwm@7000a000 {
                status = "okay";
        };
index d4438e30de456c70047457f6ee974ac31a6f686f..ed7e1009326cd748628c5422849bfffad2a3b21e 100644 (file)
@@ -10,6 +10,8 @@
        aliases {
                rtc0 = "/i2c@7000d000/tps6586x@34";
                rtc1 = "/rtc@7000e000";
+               serial0 = &uarta;
+               serial1 = &uartc;
        };
 
        memory {
index a1d4bf9895d74c8b0efb7d2fe948a9fcd602b25e..ea282c7c0ca5645394a28e313fbad1deac339882 100644 (file)
@@ -10,6 +10,7 @@
        aliases {
                rtc0 = "/i2c@7000d000/tps6586x@34";
                rtc1 = "/rtc@7000e000";
+               serial0 = &uartd;
        };
 
        memory {
index 80e7d386ce3452e3776e70771233eea336a81e98..13d4e6185275f43c3f74fbeb0397d97b0348f9fb 100644 (file)
@@ -7,6 +7,7 @@
        aliases {
                rtc0 = "/i2c@7000d000/tps6586x@34";
                rtc1 = "/rtc@7000e000";
+               serial0 = &uartd;
        };
 
        memory {
index 5ad87979ab13ff68527f3b6c8a1ba9bb51e2bda5..d99af4ef9c6444f73e7044c7447557fbca4b4ee1 100644 (file)
@@ -10,6 +10,7 @@
        aliases {
                rtc0 = "/i2c@7000c500/rtc@56";
                rtc1 = "/rtc@7000e000";
+               serial0 = &uarta;
        };
 
        memory {
index ca8484cccddccc32313649e1abfd644b527f50a3..04c58e9ca490bb8bf205b4608d371bbecf5f3f61 100644 (file)
@@ -10,6 +10,7 @@
        aliases {
                rtc0 = "/i2c@7000d000/tps6586x@34";
                rtc1 = "/rtc@7000e000";
+               serial0 = &uartd;
        };
 
        memory {
index 1843725785c90f1f2518bade455af7dead4c6ec8..340d81108df1a232fcefe64c81bdb9372a4c814c 100644 (file)
@@ -10,6 +10,7 @@
        aliases {
                rtc0 = "/i2c@7000d000/max8907@3c";
                rtc1 = "/rtc@7000e000";
+               serial0 = &uarta;
        };
 
        memory {
index 3b374c49d04d962478aebc62799bcce5b31aa6dd..8acf5d85c99da5b0077f6ce1b80c2ba08d45865c 100644 (file)
@@ -9,14 +9,6 @@
        compatible = "nvidia,tegra20";
        interrupt-parent = <&intc>;
 
-       aliases {
-               serial0 = &uarta;
-               serial1 = &uartb;
-               serial2 = &uartc;
-               serial3 = &uartd;
-               serial4 = &uarte;
-       };
-
        host1x@50000000 {
                compatible = "nvidia,tegra20-host1x", "simple-bus";
                reg = <0x50000000 0x00024000>;
index 45d40f024585d95a53928e36d351db05aa514592..6236bdecb48ba08891896f6967199aba6e2a6680 100644 (file)
                rtc0 = "/i2c@7000c000/rtc@68";
                rtc1 = "/i2c@7000d000/tps65911@2d";
                rtc2 = "/rtc@7000e000";
+               serial0 = &uarta;
+               serial1 = &uartb;
+               serial2 = &uartc;
+               serial3 = &uartd;
        };
 
        pcie-controller@00003000 {
index cee8f2246fdb2467fbde27bae612a0752d7f6da2..6b157eeabcc5c9b07009c4d91a291122b3732887 100644 (file)
@@ -9,6 +9,7 @@
        aliases {
                rtc0 = "/i2c@7000d000/tps65911@2d";
                rtc1 = "/rtc@7000e000";
+               serial0 = &uarta;
        };
 
        memory {
index 20637954624425795453cc78699e674276de5430..a1b682ea01bd70ab94025cd12a4d5205d45f9db7 100644 (file)
@@ -30,6 +30,8 @@
        aliases {
                rtc0 = "/i2c@7000d000/tps65911@2d";
                rtc1 = "/rtc@7000e000";
+               serial0 = &uarta;
+               serial1 = &uartc;
        };
 
        memory {
index 7793abd5bef132388100e8a0c1aa4ca79e7ed803..4d3ddc58564126433410c17b5c3ef569532a9aa1 100644 (file)
@@ -10,6 +10,9 @@
                rtc0 = "/i2c@7000c000/rtc@68";
                rtc1 = "/i2c@7000d000/tps65911@2d";
                rtc2 = "/rtc@7000e000";
+               serial0 = &uarta;
+               serial1 = &uartb;
+               serial2 = &uartd;
        };
 
        host1x@50000000 {
index aa6ccea13d308036e853b58bafe840d7c3450e87..b270b9e3d4554407157be95cadd71c9b5e902eeb 100644 (file)
@@ -9,14 +9,6 @@
        compatible = "nvidia,tegra30";
        interrupt-parent = <&intc>;
 
-       aliases {
-               serial0 = &uarta;
-               serial1 = &uartb;
-               serial2 = &uartc;
-               serial3 = &uartd;
-               serial4 = &uarte;
-       };
-
        pcie-controller@00003000 {
                compatible = "nvidia,tegra30-pcie";
                device_type = "pci";
index 72058b8a6f4d4ccce4a8e5a740f82ba0321ef561..e21ef830a48365a06db80d0127fa5a3f55f17f71 100644 (file)
@@ -142,11 +142,13 @@ CONFIG_MMC_DW_IDMAC=y
 CONFIG_MMC_DW_EXYNOS=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_MAX77686=y
+CONFIG_RTC_DRV_MAX77802=y
 CONFIG_RTC_DRV_S5M=y
 CONFIG_RTC_DRV_S3C=y
 CONFIG_DMADEVICES=y
 CONFIG_PL330_DMA=y
 CONFIG_COMMON_CLK_MAX77686=y
+CONFIG_COMMON_CLK_MAX77802=y
 CONFIG_COMMON_CLK_S2MPS11=y
 CONFIG_EXYNOS_IOMMU=y
 CONFIG_IIO=y
index 3487046d8a7844b68bc2365c05dfc500e3fca2c9..9d7a32f93fcf2e93a66b42b3352b7b3119d9ec0e 100644 (file)
@@ -217,6 +217,7 @@ CONFIG_I2C_CADENCE=y
 CONFIG_I2C_DESIGNWARE_PLATFORM=y
 CONFIG_I2C_EXYNOS5=y
 CONFIG_I2C_MV64XXX=y
+CONFIG_I2C_S3C2410=y
 CONFIG_I2C_SIRF=y
 CONFIG_I2C_TEGRA=y
 CONFIG_I2C_ST=y
index fc44d3761f9e7d36eb8ff4911ff0120a63e7584f..ce73ab6354149f8c490319bdeb6acdbc92cd784c 100644 (file)
@@ -44,16 +44,6 @@ struct cpu_context_save {
        __u32   extra[2];               /* Xscale 'acc' register, etc */
 };
 
-struct arm_restart_block {
-       union {
-               /* For user cache flushing */
-               struct {
-                       unsigned long start;
-                       unsigned long end;
-               } cache;
-       };
-};
-
 /*
  * low level task data that entry.S needs immediate access to.
  * __switch_to() assumes cpu_context follows immediately after cpu_domain.
@@ -79,7 +69,6 @@ struct thread_info {
        unsigned long           thumbee_state;  /* ThumbEE Handler Base register */
 #endif
        struct restart_block    restart_block;
-       struct arm_restart_block        arm_restart_block;
 };
 
 #define INIT_THREAD_INFO(tsk)                                          \
index 0c8b10801d36ad6a25806892ea283c7b93d28f61..9f5d81881eb6da9bdd599a7321cf83fbdcb0a0e2 100644 (file)
@@ -533,8 +533,6 @@ static int bad_syscall(int n, struct pt_regs *regs)
        return regs->ARM_r0;
 }
 
-static long do_cache_op_restart(struct restart_block *);
-
 static inline int
 __do_cache_op(unsigned long start, unsigned long end)
 {
@@ -543,24 +541,8 @@ __do_cache_op(unsigned long start, unsigned long end)
        do {
                unsigned long chunk = min(PAGE_SIZE, end - start);
 
-               if (signal_pending(current)) {
-                       struct thread_info *ti = current_thread_info();
-
-                       ti->restart_block = (struct restart_block) {
-                               .fn     = do_cache_op_restart,
-                       };
-
-                       ti->arm_restart_block = (struct arm_restart_block) {
-                               {
-                                       .cache = {
-                                               .start  = start,
-                                               .end    = end,
-                                       },
-                               },
-                       };
-
-                       return -ERESTART_RESTARTBLOCK;
-               }
+               if (fatal_signal_pending(current))
+                       return 0;
 
                ret = flush_cache_user_range(start, start + chunk);
                if (ret)
@@ -573,15 +555,6 @@ __do_cache_op(unsigned long start, unsigned long end)
        return 0;
 }
 
-static long do_cache_op_restart(struct restart_block *unused)
-{
-       struct arm_restart_block *restart_block;
-
-       restart_block = &current_thread_info()->arm_restart_block;
-       return __do_cache_op(restart_block->cache.start,
-                            restart_block->cache.end);
-}
-
 static inline int
 do_cache_op(unsigned long start, unsigned long end, int flags)
 {
index 57a403a5c22bf9e174ec88a0377b4ab07c3b0a29..8664ff17cbbeaf531b03174e1524cc00a6e86849 100644 (file)
@@ -197,7 +197,8 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
        pgd = pgdp + pgd_index(addr);
        do {
                next = kvm_pgd_addr_end(addr, end);
-               unmap_puds(kvm, pgd, addr, next);
+               if (!pgd_none(*pgd))
+                       unmap_puds(kvm, pgd, addr, next);
        } while (pgd++, addr = next, addr != end);
 }
 
@@ -834,6 +835,11 @@ static bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
        return kvm_vcpu_dabt_iswrite(vcpu);
 }
 
+static bool kvm_is_device_pfn(unsigned long pfn)
+{
+       return !pfn_valid(pfn);
+}
+
 static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
                          struct kvm_memory_slot *memslot, unsigned long hva,
                          unsigned long fault_status)
@@ -904,7 +910,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
        if (is_error_pfn(pfn))
                return -EFAULT;
 
-       if (kvm_is_mmio_pfn(pfn))
+       if (kvm_is_device_pfn(pfn))
                mem_type = PAGE_S2_DEVICE;
 
        spin_lock(&kvm->mmu_lock);
index 2bdc3233abe2bcc78c527bf8efe4b0032a5880dc..044b51185fccb2e68c1f89c4efb3822704d28488 100644 (file)
@@ -400,6 +400,8 @@ int __init coherency_init(void)
                 type == COHERENCY_FABRIC_TYPE_ARMADA_380)
                armada_375_380_coherency_init(np);
 
+       of_node_put(np);
+
        return 0;
 }
 
index a6503d8c77de07c76288de39d6c4ede94db91090..004ed92ee598df3c9369e8bfbf227e48173135e0 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <linux/gpio.h>
index b222f68d55b7251ef2d8da0e2fcd50005fdfdef4..66f67816a844623977a4595ef23642ed381b3549 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <linux/gpio.h>
index e709835344038a5a1fbace09bcf68d554c27aa8b..0e912aff53ded12a956d8e190f5e0fb130d767ab 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
  */
 
 #include <linux/clk.h>
index 79c47847f2004d5921d3061ff7a73f120a1b4ce3..d649ade4a202a2794abb107fd5b252047b5958c9 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <linux/of_platform.h>
index 1cf2c75dacfb49b94c5a26c03d6edb15c064baf1..f27b5a833bf0bb966a7046ae18a64f3f306f3134 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <linux/mfd/tmio.h>
index 46aa540133d6b81cb05053ffaab7a1a28aa21553..451ba624ce6e343d023ddfb5595624484cfeb781 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <linux/dma-mapping.h>
 #include <linux/kernel.h>
 #include <linux/of_platform.h>
-#include <linux/platform_data/rcar-du.h>
 
 #include <asm/mach/arch.h>
 
-#include "clock.h"
 #include "common.h"
-#include "irqs.h"
 #include "r8a7791.h"
 #include "rcar-gen2.h"
 
-/* DU */
-static struct rcar_du_encoder_data koelsch_du_encoders[] = {
-       {
-               .type = RCAR_DU_ENCODER_NONE,
-               .output = RCAR_DU_OUTPUT_LVDS0,
-               .connector.lvds.panel = {
-                       .width_mm = 210,
-                       .height_mm = 158,
-                       .mode = {
-                               .pixelclock = 65000000,
-                               .hactive = 1024,
-                               .hfront_porch = 20,
-                               .hback_porch = 160,
-                               .hsync_len = 136,
-                               .vactive = 768,
-                               .vfront_porch = 3,
-                               .vback_porch = 29,
-                               .vsync_len = 6,
-                       },
-               },
-       },
-};
-
-static struct rcar_du_platform_data koelsch_du_pdata = {
-       .encoders = koelsch_du_encoders,
-       .num_encoders = ARRAY_SIZE(koelsch_du_encoders),
-};
-
-static const struct resource du_resources[] __initconst = {
-       DEFINE_RES_MEM(0xfeb00000, 0x40000),
-       DEFINE_RES_MEM_NAMED(0xfeb90000, 0x1c, "lvds.0"),
-       DEFINE_RES_IRQ(gic_spi(256)),
-       DEFINE_RES_IRQ(gic_spi(268)),
-};
-
-static void __init koelsch_add_du_device(void)
-{
-       struct platform_device_info info = {
-               .name = "rcar-du-r8a7791",
-               .id = -1,
-               .res = du_resources,
-               .num_res = ARRAY_SIZE(du_resources),
-               .data = &koelsch_du_pdata,
-               .size_data = sizeof(koelsch_du_pdata),
-               .dma_mask = DMA_BIT_MASK(32),
-       };
-
-       platform_device_register_full(&info);
-}
-
-/*
- * This is a really crude hack to provide clkdev support to platform
- * devices until they get moved to DT.
- */
-static const struct clk_name clk_names[] __initconst = {
-       { "du0", "du.0", "rcar-du-r8a7791" },
-       { "du1", "du.1", "rcar-du-r8a7791" },
-       { "lvds0", "lvds.0", "rcar-du-r8a7791" },
-};
-
-static void __init koelsch_add_standard_devices(void)
-{
-       shmobile_clk_workaround(clk_names, ARRAY_SIZE(clk_names), false);
-       of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-
-       koelsch_add_du_device();
-}
-
 static const char * const koelsch_boards_compat_dt[] __initconst = {
        "renesas,koelsch",
        "renesas,koelsch-reference",
@@ -110,7 +34,6 @@ DT_MACHINE_START(KOELSCH_DT, "koelsch")
        .smp            = smp_ops(r8a7791_smp_ops),
        .init_early     = shmobile_init_delay,
        .init_time      = rcar_gen2_timer_init,
-       .init_machine   = koelsch_add_standard_devices,
        .init_late      = shmobile_init_late,
        .reserve        = rcar_gen2_reserve,
        .dt_compat      = koelsch_boards_compat_dt,
index 7111b5c1d67b764f79daec420390fea7f408c92c..3a6a2766dc2b8699a5a6d47f89dbedda4cd2c996 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <linux/dma-mapping.h>
index d9cdf9a97e2390b4f63cb4b22b11246b2088bea6..f2ef759b6e969cc811f283c7700ef18de0f057ac 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <linux/delay.h>
index 77e36fa0b14216bb644149b2969267961ae43367..7c9b63bdde9fa458c3ddc7aa751030e0484beaf2 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <linux/delay.h>
index bc4b48357ddea891ccb0365ba267325adff374d8..fa06bdba61df19d33fe6990eaa0a867855434c98 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <linux/dma-mapping.h>
 #include <linux/init.h>
 #include <linux/of_platform.h>
-#include <linux/platform_data/rcar-du.h>
 
 #include <asm/mach/arch.h>
 
-#include "clock.h"
 #include "common.h"
-#include "irqs.h"
 #include "r8a7790.h"
 #include "rcar-gen2.h"
 
-/* DU */
-static struct rcar_du_encoder_data lager_du_encoders[] = {
-       {
-               .type = RCAR_DU_ENCODER_VGA,
-               .output = RCAR_DU_OUTPUT_DPAD0,
-       }, {
-               .type = RCAR_DU_ENCODER_NONE,
-               .output = RCAR_DU_OUTPUT_LVDS1,
-               .connector.lvds.panel = {
-                       .width_mm = 210,
-                       .height_mm = 158,
-                       .mode = {
-                               .pixelclock = 65000000,
-                               .hactive = 1024,
-                               .hfront_porch = 20,
-                               .hback_porch = 160,
-                               .hsync_len = 136,
-                               .vactive = 768,
-                               .vfront_porch = 3,
-                               .vback_porch = 29,
-                               .vsync_len = 6,
-                       },
-               },
-       },
-};
-
-static struct rcar_du_platform_data lager_du_pdata = {
-       .encoders = lager_du_encoders,
-       .num_encoders = ARRAY_SIZE(lager_du_encoders),
-};
-
-static const struct resource du_resources[] __initconst = {
-       DEFINE_RES_MEM(0xfeb00000, 0x70000),
-       DEFINE_RES_MEM_NAMED(0xfeb90000, 0x1c, "lvds.0"),
-       DEFINE_RES_MEM_NAMED(0xfeb94000, 0x1c, "lvds.1"),
-       DEFINE_RES_IRQ(gic_spi(256)),
-       DEFINE_RES_IRQ(gic_spi(268)),
-       DEFINE_RES_IRQ(gic_spi(269)),
-};
-
-static void __init lager_add_du_device(void)
-{
-       struct platform_device_info info = {
-               .name = "rcar-du-r8a7790",
-               .id = -1,
-               .res = du_resources,
-               .num_res = ARRAY_SIZE(du_resources),
-               .data = &lager_du_pdata,
-               .size_data = sizeof(lager_du_pdata),
-               .dma_mask = DMA_BIT_MASK(32),
-       };
-
-       platform_device_register_full(&info);
-}
-
-/*
- * This is a really crude hack to provide clkdev support to platform
- * devices until they get moved to DT.
- */
-static const struct clk_name clk_names[] __initconst = {
-       { "du0", "du.0", "rcar-du-r8a7790" },
-       { "du1", "du.1", "rcar-du-r8a7790" },
-       { "du2", "du.2", "rcar-du-r8a7790" },
-       { "lvds0", "lvds.0", "rcar-du-r8a7790" },
-       { "lvds1", "lvds.1", "rcar-du-r8a7790" },
-};
-
-static void __init lager_add_standard_devices(void)
-{
-       shmobile_clk_workaround(clk_names, ARRAY_SIZE(clk_names), false);
-       of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-
-       lager_add_du_device();
-}
-
 static const char *lager_boards_compat_dt[] __initdata = {
        "renesas,lager",
        "renesas,lager-reference",
@@ -116,7 +33,6 @@ DT_MACHINE_START(LAGER_DT, "lager")
        .smp            = smp_ops(r8a7790_smp_ops),
        .init_early     = shmobile_init_delay,
        .init_time      = rcar_gen2_timer_init,
-       .init_machine   = lager_add_standard_devices,
        .init_late      = shmobile_init_late,
        .reserve        = rcar_gen2_reserve,
        .dt_compat      = lager_boards_compat_dt,
index 571327b1c942c138fbba5cfe8e5ea03d7896ccb1..f8197eb6e5669ada1b8ddd57e7bb09e42bedfe62 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <linux/gpio.h>
@@ -36,7 +32,6 @@
 #include <linux/pinctrl/machine.h>
 #include <linux/platform_data/camera-rcar.h>
 #include <linux/platform_data/gpio-rcar.h>
-#include <linux/platform_data/rcar-du.h>
 #include <linux/platform_data/usb-rcar-gen2-phy.h>
 #include <linux/platform_device.h>
 #include <linux/phy.h>
  *
  */
 
-/* DU */
-static struct rcar_du_encoder_data lager_du_encoders[] = {
-       {
-               .type = RCAR_DU_ENCODER_VGA,
-               .output = RCAR_DU_OUTPUT_DPAD0,
-       }, {
-               .type = RCAR_DU_ENCODER_NONE,
-               .output = RCAR_DU_OUTPUT_LVDS1,
-               .connector.lvds.panel = {
-                       .width_mm = 210,
-                       .height_mm = 158,
-                       .mode = {
-                               .pixelclock = 65000000,
-                               .hactive = 1024,
-                               .hfront_porch = 20,
-                               .hback_porch = 160,
-                               .hsync_len = 136,
-                               .vactive = 768,
-                               .vfront_porch = 3,
-                               .vback_porch = 29,
-                               .vsync_len = 6,
-                       },
-               },
-       },
-};
-
-static const struct rcar_du_platform_data lager_du_pdata __initconst = {
-       .encoders = lager_du_encoders,
-       .num_encoders = ARRAY_SIZE(lager_du_encoders),
-};
-
-static const struct resource du_resources[] __initconst = {
-       DEFINE_RES_MEM(0xfeb00000, 0x70000),
-       DEFINE_RES_MEM_NAMED(0xfeb90000, 0x1c, "lvds.0"),
-       DEFINE_RES_MEM_NAMED(0xfeb94000, 0x1c, "lvds.1"),
-       DEFINE_RES_IRQ(gic_spi(256)),
-       DEFINE_RES_IRQ(gic_spi(268)),
-       DEFINE_RES_IRQ(gic_spi(269)),
-};
-
-static void __init lager_add_du_device(void)
-{
-       struct platform_device_info info = {
-               .name = "rcar-du-r8a7790",
-               .id = -1,
-               .res = du_resources,
-               .num_res = ARRAY_SIZE(du_resources),
-               .data = &lager_du_pdata,
-               .size_data = sizeof(lager_du_pdata),
-               .dma_mask = DMA_BIT_MASK(32),
-       };
-
-       platform_device_register_full(&info);
-}
-
 /* LEDS */
 static struct gpio_led lager_leds[] = {
        {
@@ -804,8 +744,6 @@ static void __init lager_add_standard_devices(void)
 
        platform_device_register_full(&ether_info);
 
-       lager_add_du_device();
-
        platform_device_register_resndata(NULL, "qspi", 0,
                                          qspi_resources,
                                          ARRAY_SIZE(qspi_resources),
index ca5d34b92aa7fc8e70d55cf4e6c2cf31aa103e13..ed1087031c5def92376b7acc100ee9dd8234cff2 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/delay.h>
 #include <linux/kernel.h>
index 38d9cdd26587ebf3c843ea25d09d26674b9430c4..f0757bbaff872a428f6ac889cff47fd811d33ea8 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <linux/clk/shmobile.h>
index ce33d7825c49a818a2bb1927299be684a7196544..598f704f76ae7420c96f420c9d3c9b63bbf09edc 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <linux/kernel.h>
@@ -31,7 +27,6 @@
 #include <linux/pinctrl/machine.h>
 #include <linux/platform_data/camera-rcar.h>
 #include <linux/platform_data/gpio-rcar.h>
-#include <linux/platform_data/rcar-du.h>
 #include <linux/platform_data/usb-rcar-phy.h>
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
@@ -175,62 +170,6 @@ static struct platform_device hspi_device = {
        .num_resources  = ARRAY_SIZE(hspi_resources),
 };
 
-/*
- * DU
- *
- * The panel only specifies the [hv]display and [hv]total values. The position
- * and width of the sync pulses don't matter, they're copied from VESA timings.
- */
-static struct rcar_du_encoder_data du_encoders[] = {
-       {
-               .type = RCAR_DU_ENCODER_VGA,
-               .output = RCAR_DU_OUTPUT_DPAD0,
-       }, {
-               .type = RCAR_DU_ENCODER_LVDS,
-               .output = RCAR_DU_OUTPUT_DPAD1,
-               .connector.lvds.panel = {
-                       .width_mm = 210,
-                       .height_mm = 158,
-                       .mode = {
-                               .pixelclock = 65000000,
-                               .hactive = 1024,
-                               .hfront_porch = 20,
-                               .hback_porch = 160,
-                               .hsync_len = 136,
-                               .vactive = 768,
-                               .vfront_porch = 3,
-                               .vback_porch = 29,
-                               .vsync_len = 6,
-                       },
-               },
-       },
-};
-
-static const struct rcar_du_platform_data du_pdata __initconst = {
-       .encoders = du_encoders,
-       .num_encoders = ARRAY_SIZE(du_encoders),
-};
-
-static const struct resource du_resources[] __initconst = {
-       DEFINE_RES_MEM(0xfff80000, 0x40000),
-       DEFINE_RES_IRQ(gic_iid(0x3f)),
-};
-
-static void __init marzen_add_du_device(void)
-{
-       struct platform_device_info info = {
-               .name = "rcar-du-r8a7779",
-               .id = -1,
-               .res = du_resources,
-               .num_res = ARRAY_SIZE(du_resources),
-               .data = &du_pdata,
-               .size_data = sizeof(du_pdata),
-               .dma_mask = DMA_BIT_MASK(32),
-       };
-
-       platform_device_register_full(&info);
-}
-
 /* LEDS */
 static struct gpio_led marzen_leds[] = {
        {
@@ -389,7 +328,6 @@ static void __init marzen_init(void)
        platform_device_register_full(&vin1_info);
        platform_device_register_full(&vin3_info);
        platform_add_devices(marzen_devices, ARRAY_SIZE(marzen_devices));
-       marzen_add_du_device();
 }
 
 static const char *marzen_boards_compat_dt[] __initdata = {
index c2330ea1802c6142dc4319836afe1490a7f4d5aa..1cf44dc6d718bcc0da183bc4e19aa595dfc7d08f 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/init.h>
 #include <linux/io.h>
index 0794f0426e7044810ec46d695c4a9e0c87abd38b..9cac8247c72b6e4565e34523a19519815a19f6c1 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -455,7 +451,7 @@ enum {
        MSTP128, MSTP127, MSTP125,
        MSTP116, MSTP111, MSTP100, MSTP117,
 
-       MSTP230,
+       MSTP230, MSTP229,
        MSTP222,
        MSTP218, MSTP217, MSTP216, MSTP214,
        MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
@@ -474,11 +470,12 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP127] = SH_CLK_MSTP32(&div4_clks[DIV4_S],   SMSTPCR1, 27, 0), /* CEU20 */
        [MSTP125] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 25, 0), /* TMU0 */
        [MSTP117] = SH_CLK_MSTP32(&div4_clks[DIV4_B],   SMSTPCR1, 17, 0), /* LCDC1 */
-       [MSTP116] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */
+       [MSTP116] = SH_CLK_MSTP32(&div4_clks[DIV4_HPP], SMSTPCR1, 16, 0), /* IIC0 */
        [MSTP111] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 11, 0), /* TMU1 */
        [MSTP100] = SH_CLK_MSTP32(&div4_clks[DIV4_B],   SMSTPCR1,  0, 0), /* LCDC0 */
 
        [MSTP230] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 30, 0), /* SCIFA6 */
+       [MSTP229] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],  SMSTPCR2, 29, 0), /* INTCA */
        [MSTP222] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 22, 0), /* SCIFA7 */
        [MSTP218] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],  SMSTPCR2, 18, 0), /* DMAC1 */
        [MSTP217] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],  SMSTPCR2, 17, 0), /* DMAC2 */
@@ -575,6 +572,10 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("sh-dma-engine.0",        &mstp_clks[MSTP218]),
        CLKDEV_DEV_ID("sh-sci.7",               &mstp_clks[MSTP222]),
        CLKDEV_DEV_ID("e6cd0000.serial",        &mstp_clks[MSTP222]),
+       CLKDEV_DEV_ID("renesas_intc_irqpin.0",  &mstp_clks[MSTP229]),
+       CLKDEV_DEV_ID("renesas_intc_irqpin.1",  &mstp_clks[MSTP229]),
+       CLKDEV_DEV_ID("renesas_intc_irqpin.2",  &mstp_clks[MSTP229]),
+       CLKDEV_DEV_ID("renesas_intc_irqpin.3",  &mstp_clks[MSTP229]),
        CLKDEV_DEV_ID("sh-sci.6",               &mstp_clks[MSTP230]),
        CLKDEV_DEV_ID("e6cc0000.serial",        &mstp_clks[MSTP230]),
 
index 67980a08a601bfee89430fa48be2141ab3d82bb5..e8510c35558c11637d35e08d78690fbe87eff7c6 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 /*
index c51f9db3f66fb2f9408094cc112b52c3d716d534..fa8ab2cc91878af5f568b58521b62d3b9340a96e 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/bitops.h>
 #include <linux/init.h>
index 126ddafad5265dc62793fd6e7f25aea16b7c42e1..f9bbc5f0a9a12a8f61510e8d72df280149548c33 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/init.h>
 #include <linux/io.h>
@@ -68,7 +64,7 @@
 
 #define SDCKCR         0xE6150074
 #define SD2CKCR                0xE6150078
-#define SD3CKCR                0xE615007C
+#define SD3CKCR                0xE615026C
 #define MMC0CKCR       0xE6150240
 #define MMC1CKCR       0xE6150244
 #define SSPCKCR                0xE6150248
index 453b23129cfa0cd3903e7ebdc3aaef8009bb3542..82143ca3bae9ab7b72877c407425010bbcac51aa 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/init.h>
 #include <linux/io.h>
index 7071676145c497ae911fd7199b721692c71c2b8e..3bc92f46060e9ce55c793ea6104b6214d84b8bb7 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
index 02a6f45a0b9e1c832d5c5d6bfcb79395a42363a2..6b4c1f313cc987c15ab0028b0f82ed4cde98a0fb 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
index 806f94038cc49a8421f85d305a018113a59009b8..1f81ad747153b6bd0ae90b9bc48ecb7a6200b65c 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
index f2e79f2376e19f6f0a227af94bf2e4fc3be76409..e329ccbd0a6734f1e1c477f63ec878779cbce3d5 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
index f45dde701d7b598c0bc7f2544ea438b0ea19327e..69df8bfac1672202073d5096631e1897857f5a5e 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
  */
 
 #include <linux/linkage.h>
index e2af00b1bd9dc465eefec06ad84398b41dda1657..1ccf49cb485fd96ae5f96c5d2f85d06f8dc7d02e 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
index 44457a94897b28708c83cbb12a394ab857b860f1..9e3618028accea72442a4ca8fc1a09b36f267dd2 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
index f369b4b0863d0bb38a2705e7c2fc12e83438c340..ca7805ad7ea3d64ea24c487f1ff1c5981e0f6e7f 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #ifndef __ASM_R8A7740_H__
index f4076a50e970a357c8c9dfbbbc07d4f6d61ada25..9086dfc6746af9376c70cc9804e37c127bc06928 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #ifndef __ASM_R8A7778_H__
 #define __ASM_R8A7778_H__
index b06a9e8f59a5fb7a232f00a747e1715bc23b5a71..aad97be9cbe1b0fabe069136e2e264cc51de8a24 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
index 4122104359f98d909ae03a923256b479972ff3e0..171174777b6f8d3fa447cd183eafbf3d3b9ff291 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <linux/kernel.h>
index 53f40b70680de9087fa90c0e61ae2711ac8a0fc7..b88b88a40a3c6319686d1db1a292a63d9cba6e8c 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/irq.h>
 #include <linux/kernel.h>
index 8894e1b7ab0e65bbf66975ac36ca9b2b5917604f..fe15dd26d15dc3ec5a33a94528b066595849eadb 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
index 85fe016d6a872a6233effacc6118f2195d8cdbc8..8ec784fc6b266443bfd32881d06134dde919dc16 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <linux/kernel.h>
index 136078ab9407cc2d2f31b43b213c105e6bbaaa4e..d08e75cceaab3ead2a84eb294bfa08ddcbd6d409 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
index 877fdeb985d0c240e52eea158eeb16edd1b2ef68..ec7d97dca4de2108cbb3a7bbb3ee5b52dd0d8f95 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <linux/irq.h>
index 35d78639244fd805d08d2f44954a5f889379ff6c..d930925f8f1a1ee8837316f5ab30de3f0839cace 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <linux/irq.h>
index 42d5b43089235375e1a1d75b440a32d8940ac1ed..a669377aea5798194e65451aaf2c51e99d36e808 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <linux/clk/shmobile.h>
index d646c8d12423a600332f5e5876f75445426fdca3..e81c38538e13f12e639e0ffa47a140cd21f4e1f7 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
index b7bd8e50966879608cde0e5c152cefb12185d9f1..f2e01dc22a08b75545c4482fdbe803cb42d3b554 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -26,6 +22,7 @@
 #include <linux/of_platform.h>
 #include <linux/delay.h>
 #include <linux/input.h>
+#include <linux/i2c/i2c-sh_mobile.h>
 #include <linux/io.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_dma.h>
@@ -192,11 +189,18 @@ static struct resource i2c4_resources[] = {
        },
 };
 
+static struct i2c_sh_mobile_platform_data i2c_platform_data = {
+       .clks_per_count = 2,
+};
+
 static struct platform_device i2c0_device = {
        .name           = "i2c-sh_mobile",
        .id             = 0,
        .resource       = i2c0_resources,
        .num_resources  = ARRAY_SIZE(i2c0_resources),
+       .dev            = {
+               .platform_data  = &i2c_platform_data,
+       },
 };
 
 static struct platform_device i2c1_device = {
@@ -204,6 +208,9 @@ static struct platform_device i2c1_device = {
        .id             = 1,
        .resource       = i2c1_resources,
        .num_resources  = ARRAY_SIZE(i2c1_resources),
+       .dev            = {
+               .platform_data  = &i2c_platform_data,
+       },
 };
 
 static struct platform_device i2c2_device = {
@@ -211,6 +218,9 @@ static struct platform_device i2c2_device = {
        .id             = 2,
        .resource       = i2c2_resources,
        .num_resources  = ARRAY_SIZE(i2c2_resources),
+       .dev            = {
+               .platform_data  = &i2c_platform_data,
+       },
 };
 
 static struct platform_device i2c3_device = {
@@ -218,6 +228,9 @@ static struct platform_device i2c3_device = {
        .id             = 3,
        .resource       = i2c3_resources,
        .num_resources  = ARRAY_SIZE(i2c3_resources),
+       .dev            = {
+               .platform_data  = &i2c_platform_data,
+       },
 };
 
 static struct platform_device i2c4_device = {
@@ -225,6 +238,9 @@ static struct platform_device i2c4_device = {
        .id             = 4,
        .resource       = i2c4_resources,
        .num_resources  = ARRAY_SIZE(i2c4_resources),
+       .dev            = {
+               .platform_data  = &i2c_platform_data,
+       },
 };
 
 static const struct sh_dmae_slave_config sh73a0_dmae_slaves[] = {
index 9782862899e81f1895ae0f1312cdfa5623d58914..146b8de16432fe3ca573243ded57e8dc8208218d 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
  */
 
 #include <linux/linkage.h>
index 6ff1df1df9a752c313514284a09a0e747e906c4c..baff3b5efed8c31b5e1c5cd18e21e4348dcc1360 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
index 3100e355c3fde4e589aa015a50a68e7b1f57da85..3f761f8390430d61fa7753511412d06827eaf284 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
index 22d8f87b23e9006b206a3c04fe9720a384926c81..c16dbfe9836c527de5116c5620434ffb1ced2ef6 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
index 87c6be1e79bd989d24c64ccfc4a95342be5ddc4d..1081b763e0f390d627c2ce7f561a7533bc19872b 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
  */
 #include <linux/platform_device.h>
 #include <linux/clocksource.h>
index da7be13aecce3cd8d12de9b64c10b6e3facf252b..ab95f5391a2b631e5cace17bbb176766e7d410bf 100644 (file)
@@ -99,42 +99,42 @@ static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg)
 
 static void tegra_mask(struct irq_data *d)
 {
-       if (d->irq < FIRST_LEGACY_IRQ)
+       if (d->hwirq < FIRST_LEGACY_IRQ)
                return;
 
-       tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_CLR);
+       tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IER_CLR);
 }
 
 static void tegra_unmask(struct irq_data *d)
 {
-       if (d->irq < FIRST_LEGACY_IRQ)
+       if (d->hwirq < FIRST_LEGACY_IRQ)
                return;
 
-       tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_SET);
+       tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IER_SET);
 }
 
 static void tegra_ack(struct irq_data *d)
 {
-       if (d->irq < FIRST_LEGACY_IRQ)
+       if (d->hwirq < FIRST_LEGACY_IRQ)
                return;
 
-       tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR);
+       tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_CLR);
 }
 
 static void tegra_eoi(struct irq_data *d)
 {
-       if (d->irq < FIRST_LEGACY_IRQ)
+       if (d->hwirq < FIRST_LEGACY_IRQ)
                return;
 
-       tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR);
+       tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_CLR);
 }
 
 static int tegra_retrigger(struct irq_data *d)
 {
-       if (d->irq < FIRST_LEGACY_IRQ)
+       if (d->hwirq < FIRST_LEGACY_IRQ)
                return 0;
 
-       tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_SET);
+       tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_SET);
 
        return 1;
 }
@@ -142,7 +142,7 @@ static int tegra_retrigger(struct irq_data *d)
 #ifdef CONFIG_PM_SLEEP
 static int tegra_set_wake(struct irq_data *d, unsigned int enable)
 {
-       u32 irq = d->irq;
+       u32 irq = d->hwirq;
        u32 index, mask;
 
        if (irq < FIRST_LEGACY_IRQ ||
index b3a947863ac7bb7e38d47b7a640d698b55a34bbc..22ac2a6fbfe373b432f43b1041ca9cf42e189837 100644 (file)
@@ -270,7 +270,6 @@ __v7_pj4b_setup:
 /* Auxiliary Debug Modes Control 1 Register */
 #define PJ4B_STATIC_BP (1 << 2) /* Enable Static BP */
 #define PJ4B_INTER_PARITY (1 << 8) /* Disable Internal Parity Handling */
-#define PJ4B_BCK_OFF_STREX (1 << 5) /* Enable the back off of STREX instr */
 #define PJ4B_CLEAN_LINE (1 << 16) /* Disable data transfer for clean line */
 
 /* Auxiliary Debug Modes Control 2 Register */
@@ -293,7 +292,6 @@ __v7_pj4b_setup:
        /* Auxiliary Debug Modes Control 1 Register */
        mrc     p15, 1, r0, c15, c1, 1
        orr     r0, r0, #PJ4B_CLEAN_LINE
-       orr     r0, r0, #PJ4B_BCK_OFF_STREX
        orr     r0, r0, #PJ4B_INTER_PARITY
        bic     r0, r0, #PJ4B_STATIC_BP
        mcr     p15, 1, r0, c15, c1, 1
index 23259f104c66fd367d4663cbd4adafd240ffa50d..afa2b3c4df4a267e5a609c13e6e7d6461be85616 100644 (file)
@@ -535,7 +535,7 @@ ENTRY(cpu_xscale_do_suspend)
        mrc     p15, 0, r5, c15, c1, 0  @ CP access reg
        mrc     p15, 0, r6, c13, c0, 0  @ PID
        mrc     p15, 0, r7, c3, c0, 0   @ domain ID
-       mrc     p15, 0, r8, c1, c1, 0   @ auxiliary control reg
+       mrc     p15, 0, r8, c1, c0, 1   @ auxiliary control reg
        mrc     p15, 0, r9, c1, c0, 0   @ control reg
        bic     r4, r4, #2              @ clear frequency change bit
        stmia   r0, {r4 - r9}           @ store cp regs
@@ -552,7 +552,7 @@ ENTRY(cpu_xscale_do_resume)
        mcr     p15, 0, r6, c13, c0, 0  @ PID
        mcr     p15, 0, r7, c3, c0, 0   @ domain ID
        mcr     p15, 0, r1, c2, c0, 0   @ translation table base addr
-       mcr     p15, 0, r8, c1, c1, 0   @ auxiliary control reg
+       mcr     p15, 0, r8, c1, c0, 1   @ auxiliary control reg
        mov     r0, r9                  @ control register
        b       cpu_resume_mmu
 ENDPROC(cpu_xscale_do_resume)
index 4cc3b719208e0a8238930d44b409b2f7c2beb9f5..3d7c2df89946cc1d1606a4b3401115f10e44ab71 100644 (file)
@@ -424,6 +424,11 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        /* VBAR_EL1 */
        { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b0000), Op2(0b000),
          NULL, reset_val, VBAR_EL1, 0 },
+
+       /* ICC_SRE_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1100), Op2(0b101),
+         trap_raz_wi },
+
        /* CONTEXTIDR_EL1 */
        { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b001),
          access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 },
@@ -690,6 +695,10 @@ static const struct sys_reg_desc cp15_regs[] = {
        { Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
        { Op1( 0), CRn(10), CRm( 3), Op2( 0), access_vm_reg, NULL, c10_AMAIR0 },
        { Op1( 0), CRn(10), CRm( 3), Op2( 1), access_vm_reg, NULL, c10_AMAIR1 },
+
+       /* ICC_SRE */
+       { Op1( 0), CRn(12), CRm(12), Op2( 5), trap_raz_wi },
+
        { Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID },
 };
 
index ec6b9acb6bea8733a5f17bd7afe4a0a249ff4de9..dbe46f43884df183a69a2da387a941f55dbb371d 100644 (file)
@@ -1563,7 +1563,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
 
        for (i = 0; i < npages; i++) {
                pfn = gfn_to_pfn(kvm, base_gfn + i);
-               if (!kvm_is_mmio_pfn(pfn)) {
+               if (!kvm_is_reserved_pfn(pfn)) {
                        kvm_set_pmt_entry(kvm, base_gfn + i,
                                        pfn << PAGE_SHIFT,
                                _PAGE_AR_RWX | _PAGE_MA_WB);
index f43aa536c517437bc6778d6adb1d9e0212effc8c..9536ef912f594651be7e403264f3eb30c3355384 100644 (file)
@@ -2101,9 +2101,17 @@ config 64BIT_PHYS_ADDR
 config ARCH_PHYS_ADDR_T_64BIT
        def_bool 64BIT_PHYS_ADDR
 
+choice
+       prompt "SmartMIPS or microMIPS ASE support"
+
+config CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS
+       bool "None"
+       help
+         Select this if you want neither microMIPS nor SmartMIPS support
+
 config CPU_HAS_SMARTMIPS
        depends on SYS_SUPPORTS_SMARTMIPS
-       bool "Support for the SmartMIPS ASE"
+       bool "SmartMIPS"
        help
          SmartMIPS is a extension of the MIPS32 architecture aimed at
          increased security at both hardware and software level for
@@ -2115,11 +2123,13 @@ config CPU_HAS_SMARTMIPS
 
 config CPU_MICROMIPS
        depends on SYS_SUPPORTS_MICROMIPS
-       bool "Build kernel using microMIPS ISA"
+       bool "microMIPS"
        help
          When this option is enabled the kernel will be built using the
          microMIPS ISA
 
+endchoice
+
 config CPU_HAS_MSA
        bool "Support for the MIPS SIMD Architecture (EXPERIMENTAL)"
        depends on CPU_SUPPORTS_MSA
index e194f957ca8c42a0af82f0621c425308a25e4d53..fdbff44e5482cd20acc5efc798091894a3292c4f 100644 (file)
 #define WORD_INSN ".word"
 #endif
 
+#ifdef CONFIG_CPU_MICROMIPS
+#define NOP_INSN "nop32"
+#else
+#define NOP_INSN "nop"
+#endif
+
 static __always_inline bool arch_static_branch(struct static_key *key)
 {
-       asm_volatile_goto("1:\tnop\n\t"
+       asm_volatile_goto("1:\t" NOP_INSN "\n\t"
                "nop\n\t"
                ".pushsection __jump_table,  \"aw\"\n\t"
                WORD_INSN " 1b, %l[l_yes], %0\n\t"
index 7d28f95b0512ea27e1aeb7fac6f22ecc561a45fd..6d69332f21ecd53e09eebfba0de74f1c9fc1daa6 100644 (file)
 #define cpu_has_mcheck         0
 #define cpu_has_mdmx           0
 #define cpu_has_mips16         0
-#define cpu_has_mips32r1       0
 #define cpu_has_mips32r2       0
 #define cpu_has_mips3d         0
-#define cpu_has_mips64r1       0
 #define cpu_has_mips64r2       0
 #define cpu_has_mipsmt         0
 #define cpu_has_prefetch       0
index b46cd220a018d72deb84c6b8d5ea5f75d9e22a79..22a135ac91de3830e885342b834feb47ab109eff 100644 (file)
 #define MIPS_CONF6_SYND                (_ULCAST_(1) << 13)
 /* proAptiv FTLB on/off bit */
 #define MIPS_CONF6_FTLBEN      (_ULCAST_(1) << 15)
+/* FTLB probability bits */
+#define MIPS_CONF6_FTLBP_SHIFT (16)
 
 #define MIPS_CONF7_WII         (_ULCAST_(1) << 31)
 
index 4520adc8699b9c00835a4340c8da217e90dcc305..cd6e0afc683366e598eadbaf8c572e0434fdb9bf 100644 (file)
@@ -257,7 +257,11 @@ static inline void protected_flush_icache_line(unsigned long addr)
  */
 static inline void protected_writeback_dcache_line(unsigned long addr)
 {
+#ifdef CONFIG_EVA
+       protected_cachee_op(Hit_Writeback_Inv_D, addr);
+#else
        protected_cache_op(Hit_Writeback_Inv_D, addr);
+#endif
 }
 
 static inline void protected_writeback_scache_line(unsigned long addr)
index a10951090234073cae8aa6ea9d8b5542faef6a22..22a5624e2fd2dcecf4b5592097e0c18620012426 100644 (file)
@@ -301,7 +301,8 @@ do {                                                                        \
                        __get_kernel_common((x), size, __gu_ptr);       \
                else                                                    \
                        __get_user_common((x), size, __gu_ptr);         \
-       }                                                               \
+       } else                                                          \
+               (x) = 0;                                                \
                                                                        \
        __gu_err;                                                       \
 })
@@ -316,6 +317,7 @@ do {                                                                        \
        "       .insn                                           \n"     \
        "       .section .fixup,\"ax\"                          \n"     \
        "3:     li      %0, %4                                  \n"     \
+       "       move    %1, $0                                  \n"     \
        "       j       2b                                      \n"     \
        "       .previous                                       \n"     \
        "       .section __ex_table,\"a\"                       \n"     \
@@ -630,6 +632,7 @@ do {                                                                        \
        "       .insn                                           \n"     \
        "       .section .fixup,\"ax\"                          \n"     \
        "3:     li      %0, %4                                  \n"     \
+       "       move    %1, $0                                  \n"     \
        "       j       2b                                      \n"     \
        "       .previous                                       \n"     \
        "       .section __ex_table,\"a\"                       \n"     \
@@ -773,10 +776,11 @@ extern void __put_user_unaligned_unknown(void);
        "jal\t" #destination "\n\t"
 #endif
 
-#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
-#define DADDI_SCRATCH "$0"
-#else
+#if defined(CONFIG_CPU_DADDI_WORKAROUNDS) || (defined(CONFIG_EVA) &&   \
+                                             defined(CONFIG_CPU_HAS_PREFETCH))
 #define DADDI_SCRATCH "$3"
+#else
+#define DADDI_SCRATCH "$0"
 #endif
 
 extern size_t __copy_user(void *__to, const void *__from, size_t __n);
@@ -1418,7 +1422,7 @@ static inline long __strnlen_user(const char __user *s, long n)
 }
 
 /*
- * strlen_user: - Get the size of a string in user space.
+ * strnlen_user: - Get the size of a string in user space.
  * @str: The string to measure.
  *
  * Context: User context only. This function may sleep.
@@ -1427,9 +1431,7 @@ static inline long __strnlen_user(const char __user *s, long n)
  *
  * Returns the size of the string INCLUDING the terminating NUL.
  * On exception, returns 0.
- *
- * If there is a limit on the length of a valid string, you may wish to
- * consider using strnlen_user() instead.
+ * If the string is too long, returns a value greater than @n.
  */
 static inline long strnlen_user(const char __user *s, long n)
 {
index 9dc58568f230096244b5db31f01b59a106b1cb3c..d001bb1ad177e7b6e2df2fbb7e42e894784b2e91 100644 (file)
 #define __NR_seccomp                   (__NR_Linux + 316)
 #define __NR_getrandom                 (__NR_Linux + 317)
 #define __NR_memfd_create              (__NR_Linux + 318)
-#define __NR_memfd_create              (__NR_Linux + 319)
+#define __NR_bpf                       (__NR_Linux + 319)
 
 /*
  * Offset of the last N32 flavoured syscall
index 290c23b516789ba16193f7b72fa61eafbf7907b2..86495072a922f31e0214cad3b6ac71c10aaf5fa8 100644 (file)
@@ -208,7 +208,6 @@ bmips_reset_nmi_vec_end:
 END(bmips_reset_nmi_vec)
 
        .set    pop
-       .previous
 
 /***********************************************************************
  * CPU1 warm restart vector (used for second and subsequent boots).
@@ -281,5 +280,3 @@ LEAF(bmips_enable_xks01)
        jr      ra
 
 END(bmips_enable_xks01)
-
-       .previous
index e6e97d2a5c9e68cccde81ab0f181184d1e27fd13..0384b05ab5a02413cbcb11a163375029f285255f 100644 (file)
@@ -229,6 +229,7 @@ LEAF(mips_cps_core_init)
         nop
 
        .set    push
+       .set    mips32r2
        .set    mt
 
        /* Only allow 1 TC per VPE to execute... */
@@ -345,6 +346,7 @@ LEAF(mips_cps_boot_vpes)
         nop
 
        .set    push
+       .set    mips32r2
        .set    mt
 
 1:     /* Enter VPE configuration state */
index 94c4a0c0a577909849326dd38999d30ef017ab99..dc49cf30c2db46f9e0f2caef74548459c71f6714 100644 (file)
@@ -193,6 +193,32 @@ static void set_isa(struct cpuinfo_mips *c, unsigned int isa)
 static char unknown_isa[] = KERN_ERR \
        "Unsupported ISA type, c0.config0: %d.";
 
+static unsigned int calculate_ftlb_probability(struct cpuinfo_mips *c)
+{
+
+       unsigned int probability = c->tlbsize / c->tlbsizevtlb;
+
+       /*
+        * 0 = All TLBWR instructions go to FTLB
+        * 1 = 15:1: For every 16 TBLWR instructions, 15 go to the
+        * FTLB and 1 goes to the VTLB.
+        * 2 = 7:1: As above with 7:1 ratio.
+        * 3 = 3:1: As above with 3:1 ratio.
+        *
+        * Use the linear midpoint as the probability threshold.
+        */
+       if (probability >= 12)
+               return 1;
+       else if (probability >= 6)
+               return 2;
+       else
+               /*
+                * So FTLB is less than 4 times bigger than VTLB.
+                * A 3:1 ratio can still be useful though.
+                */
+               return 3;
+}
+
 static void set_ftlb_enable(struct cpuinfo_mips *c, int enable)
 {
        unsigned int config6;
@@ -203,9 +229,14 @@ static void set_ftlb_enable(struct cpuinfo_mips *c, int enable)
        case CPU_P5600:
                /* proAptiv & related cores use Config6 to enable the FTLB */
                config6 = read_c0_config6();
+               /* Clear the old probability value */
+               config6 &= ~(3 << MIPS_CONF6_FTLBP_SHIFT);
                if (enable)
                        /* Enable FTLB */
-                       write_c0_config6(config6 | MIPS_CONF6_FTLBEN);
+                       write_c0_config6(config6 |
+                                        (calculate_ftlb_probability(c)
+                                         << MIPS_CONF6_FTLBP_SHIFT)
+                                        | MIPS_CONF6_FTLBEN);
                else
                        /* Disable FTLB */
                        write_c0_config6(config6 &  ~MIPS_CONF6_FTLBEN);
@@ -757,31 +788,34 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                        c->cputype = CPU_LOONGSON2;
                        __cpu_name[cpu] = "ICT Loongson-2";
                        set_elf_platform(cpu, "loongson2e");
+                       set_isa(c, MIPS_CPU_ISA_III);
                        break;
                case PRID_REV_LOONGSON2F:
                        c->cputype = CPU_LOONGSON2;
                        __cpu_name[cpu] = "ICT Loongson-2";
                        set_elf_platform(cpu, "loongson2f");
+                       set_isa(c, MIPS_CPU_ISA_III);
                        break;
                case PRID_REV_LOONGSON3A:
                        c->cputype = CPU_LOONGSON3;
-                       c->writecombine = _CACHE_UNCACHED_ACCELERATED;
                        __cpu_name[cpu] = "ICT Loongson-3";
                        set_elf_platform(cpu, "loongson3a");
+                       set_isa(c, MIPS_CPU_ISA_M64R1);
                        break;
                case PRID_REV_LOONGSON3B_R1:
                case PRID_REV_LOONGSON3B_R2:
                        c->cputype = CPU_LOONGSON3;
                        __cpu_name[cpu] = "ICT Loongson-3";
                        set_elf_platform(cpu, "loongson3b");
+                       set_isa(c, MIPS_CPU_ISA_M64R1);
                        break;
                }
 
-               set_isa(c, MIPS_CPU_ISA_III);
                c->options = R4K_OPTS |
                             MIPS_CPU_FPU | MIPS_CPU_LLSC |
                             MIPS_CPU_32FPR;
                c->tlbsize = 64;
+               c->writecombine = _CACHE_UNCACHED_ACCELERATED;
                break;
        case PRID_IMP_LOONGSON_32:  /* Loongson-1 */
                decode_configs(c);
index 6001610cfe55f846a403633a13cfa8973a23e07a..dda800e9e73167d3637f972516743b12e25a9ddc 100644 (file)
 
 #ifdef HAVE_JUMP_LABEL
 
-#define J_RANGE_MASK ((1ul << 28) - 1)
+/*
+ * Define parameters for the standard MIPS and the microMIPS jump
+ * instruction encoding respectively:
+ *
+ * - the ISA bit of the target, either 0 or 1 respectively,
+ *
+ * - the amount the jump target address is shifted right to fit in the
+ *   immediate field of the machine instruction, either 2 or 1,
+ *
+ * - the mask determining the size of the jump region relative to the
+ *   delay-slot instruction, either 256MB or 128MB,
+ *
+ * - the jump target alignment, either 4 or 2 bytes.
+ */
+#define J_ISA_BIT      IS_ENABLED(CONFIG_CPU_MICROMIPS)
+#define J_RANGE_SHIFT  (2 - J_ISA_BIT)
+#define J_RANGE_MASK   ((1ul << (26 + J_RANGE_SHIFT)) - 1)
+#define J_ALIGN_MASK   ((1ul << J_RANGE_SHIFT) - 1)
 
 void arch_jump_label_transform(struct jump_entry *e,
                               enum jump_label_type type)
 {
+       union mips_instruction *insn_p;
        union mips_instruction insn;
-       union mips_instruction *insn_p =
-               (union mips_instruction *)(unsigned long)e->code;
 
-       /* Jump only works within a 256MB aligned region. */
-       BUG_ON((e->target & ~J_RANGE_MASK) != (e->code & ~J_RANGE_MASK));
+       insn_p = (union mips_instruction *)msk_isa16_mode(e->code);
+
+       /* Jump only works within an aligned region its delay slot is in. */
+       BUG_ON((e->target & ~J_RANGE_MASK) != ((e->code + 4) & ~J_RANGE_MASK));
 
-       /* Target must have 4 byte alignment. */
-       BUG_ON((e->target & 3) != 0);
+       /* Target must have the right alignment and ISA must be preserved. */
+       BUG_ON((e->target & J_ALIGN_MASK) != J_ISA_BIT);
 
        if (type == JUMP_LABEL_ENABLE) {
-               insn.j_format.opcode = j_op;
-               insn.j_format.target = (e->target & J_RANGE_MASK) >> 2;
+               insn.j_format.opcode = J_ISA_BIT ? mm_j32_op : j_op;
+               insn.j_format.target = e->target >> J_RANGE_SHIFT;
        } else {
                insn.word = 0; /* nop */
        }
 
        get_online_cpus();
        mutex_lock(&text_mutex);
-       *insn_p = insn;
+       if (IS_ENABLED(CONFIG_CPU_MICROMIPS)) {
+               insn_p->halfword[0] = insn.word >> 16;
+               insn_p->halfword[1] = insn.word;
+       } else
+               *insn_p = insn;
 
        flush_icache_range((unsigned long)insn_p,
                           (unsigned long)insn_p + sizeof(*insn_p));
index 31b1b763cb298841eee156c61752687c4056809d..c5c4fd54d797221256e147a8a0be5278a8806df5 100644 (file)
@@ -94,12 +94,12 @@ int rtlx_open(int index, int can_sleep)
        int ret = 0;
 
        if (index >= RTLX_CHANNELS) {
-               pr_debug(KERN_DEBUG "rtlx_open index out of range\n");
+               pr_debug("rtlx_open index out of range\n");
                return -ENOSYS;
        }
 
        if (atomic_inc_return(&channel_wqs[index].in_open) > 1) {
-               pr_debug(KERN_DEBUG "rtlx_open channel %d already opened\n", index);
+               pr_debug("rtlx_open channel %d already opened\n", index);
                ret = -EBUSY;
                goto out_fail;
        }
index d21ec57b6e952046db450d48929161b76b0710e3..f3b635f86c39c085ac67126929d4a7cec89e9702 100644 (file)
@@ -485,7 +485,7 @@ static void __init bootmem_init(void)
  * NOTE: historically plat_mem_setup did the entire platform initialization.
  *      This was rather impractical because it meant plat_mem_setup had to
  * get away without any kind of memory allocator.  To keep old code from
- * breaking plat_setup was just renamed to plat_setup and a second platform
+ * breaking plat_setup was just renamed to plat_mem_setup and a second platform
  * initialization hook for anything else was introduced.
  */
 
@@ -493,7 +493,7 @@ static int usermem __initdata;
 
 static int __init early_parse_mem(char *p)
 {
-       unsigned long start, size;
+       phys_t start, size;
 
        /*
         * If a user specifies memory size, we
index 1d57605e4615288a604403de1a7071d7112b20c0..16f1e4f2bf3c3c08896161106529b4a0c551dd9e 100644 (file)
@@ -658,13 +658,13 @@ static int signal_setup(void)
                save_fp_context = _save_fp_context;
                restore_fp_context = _restore_fp_context;
        } else {
-               save_fp_context = copy_fp_from_sigcontext;
-               restore_fp_context = copy_fp_to_sigcontext;
+               save_fp_context = copy_fp_to_sigcontext;
+               restore_fp_context = copy_fp_from_sigcontext;
        }
 #endif /* CONFIG_SMP */
 #else
-       save_fp_context = copy_fp_from_sigcontext;;
-       restore_fp_context = copy_fp_to_sigcontext;
+       save_fp_context = copy_fp_to_sigcontext;
+       restore_fp_context = copy_fp_from_sigcontext;
 #endif
 
        return 0;
index c17ef80cf65ab0f67946b515c24dab351f684acc..5d3238af9b5cc551ecb0ca9670b242b62f181a73 100644 (file)
        STOREB(t0, NBYTES-2(dst), .Ls_exc_p1\@)
 .Ldone\@:
        jr      ra
+        nop
        .if __memcpy == 1
        END(memcpy)
        .set __memcpy, 0
index 0bb9cc9dc621f705dd77b139b0985c01213f9c8e..d87e03330b29ae0dd5e27e9e84536dcc96af6f5c 100644 (file)
@@ -11,7 +11,8 @@ obj-$(CONFIG_PCI) += pci.o
 # Serial port support
 #
 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
-obj-$(CONFIG_SERIAL_8250) += serial.o
+loongson-serial-$(CONFIG_SERIAL_8250) := serial.o
+obj-y += $(loongson-serial-m) $(loongson-serial-y)
 obj-$(CONFIG_LOONGSON_UART_BASE) += uart_base.o
 obj-$(CONFIG_LOONGSON_MC146818) += rtc.o
 
index 37ed184398c6bbf8d017f130c73317ed2e548518..42323bcc5d28baf7279aacc50d15a4107c2c71b7 100644 (file)
@@ -33,6 +33,7 @@
 
 static struct node_data prealloc__node_data[MAX_NUMNODES];
 unsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES];
+EXPORT_SYMBOL(__node_distances);
 struct node_data *__node_data[MAX_NUMNODES];
 EXPORT_SYMBOL(__node_data);
 
index fa6ebd4bc9e9ae9b28a058650d0f9f87011e4c2e..c3917e251f59393a5138b3d4c557886e4fa45286 100644 (file)
@@ -299,6 +299,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
 
        local_irq_save(flags);
 
+       htw_stop();
        pid = read_c0_entryhi() & ASID_MASK;
        address &= (PAGE_MASK << 1);
        write_c0_entryhi(address | pid);
@@ -346,6 +347,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
                        tlb_write_indexed();
        }
        tlbw_use_hazard();
+       htw_start();
        flush_itlb_vm(vma);
        local_irq_restore(flags);
 }
@@ -422,6 +424,7 @@ __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
 
        local_irq_save(flags);
        /* Save old context and create impossible VPN2 value */
+       htw_stop();
        old_ctx = read_c0_entryhi();
        old_pagemask = read_c0_pagemask();
        wired = read_c0_wired();
@@ -443,6 +446,7 @@ __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
 
        write_c0_entryhi(old_ctx);
        write_c0_pagemask(old_pagemask);
+       htw_start();
 out:
        local_irq_restore(flags);
        return ret;
index b5f228e7eae6144565e34c74bf6f86e5d973a760..e3328a96e80909b758a8d619b6a0f8398399d2da 100644 (file)
@@ -1872,8 +1872,16 @@ build_r4000_tlbchange_handler_head(u32 **p, struct uasm_label **l,
        uasm_l_smp_pgtable_change(l, *p);
 #endif
        iPTE_LW(p, wr.r1, wr.r2); /* get even pte */
-       if (!m4kc_tlbp_war())
+       if (!m4kc_tlbp_war()) {
                build_tlb_probe_entry(p);
+               if (cpu_has_htw) {
+                       /* race condition happens, leaving */
+                       uasm_i_ehb(p);
+                       uasm_i_mfc0(p, wr.r3, C0_INDEX);
+                       uasm_il_bltz(p, r, wr.r3, label_leave);
+                       uasm_i_nop(p);
+               }
+       }
        return wr;
 }
 
index 20102a6d41410fbba6854edab6ee1199d50cc7fa..c427c57781865e13d52dc75ea2bb2f8db5db9ad7 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2012 MIPS Technologies, Inc.  All rights reserved.
  */
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/leds.h>
 #include <linux/platform_device.h>
 
@@ -76,8 +76,4 @@ static int __init led_init(void)
        return platform_device_register(&fled_device);
 }
 
-module_init(led_init);
-
-MODULE_AUTHOR("Chris Dearman <chris@mips.com>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("LED probe driver for SEAD-3");
+device_initcall(led_init);
index be358a8050c57c14377c1bcc44cd45b332b622b1..6b43af0a34d9dd39c4afd08526342bbdd514b068 100644 (file)
@@ -1,6 +1,10 @@
 obj-y                          += setup.o nlm_hal.o cop2-ex.o dt.o
 obj-$(CONFIG_SMP)              += wakeup.o
-obj-$(CONFIG_USB)              += usb-init.o
-obj-$(CONFIG_USB)              += usb-init-xlp2.o
-obj-$(CONFIG_SATA_AHCI)                += ahci-init.o
-obj-$(CONFIG_SATA_AHCI)                += ahci-init-xlp2.o
+ifdef CONFIG_USB
+obj-y                          += usb-init.o
+obj-y                          += usb-init-xlp2.o
+endif
+ifdef CONFIG_SATA_AHCI
+obj-y                          += ahci-init.o
+obj-y                          += ahci-init-xlp2.o
+endif
index 6854ed5097d2e61bb3f7f3e2937612a5d1058b07..83a1dfd8f0e3c34d02cbe24448f5c5407852f942 100644 (file)
@@ -92,7 +92,7 @@ static inline int unwind_user_frame(struct stackframe *old_frame,
                                /* This marks the end of the previous function,
                                   which means we overran. */
                                break;
-                       stack_size = (unsigned) stack_adjustment;
+                       stack_size = (unsigned long) stack_adjustment;
                } else if (is_ra_save_ins(&ip)) {
                        int ra_slot = ip.i_format.simmediate;
                        if (ra_slot < 0)
index a95c00f5fb9697ed90fa79d44ec887b498f680fc..a304bcc37e4fba137a5a1ee8bc792a50d7258e01 100644 (file)
@@ -107,6 +107,7 @@ static void router_recurse(klrou_t *router_a, klrou_t *router_b, int depth)
 }
 
 unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
+EXPORT_SYMBOL(__node_distances);
 
 static int __init compute_node_distance(nasid_t nasid_a, nasid_t nasid_b)
 {
index 4ca90a39d6d01af63da46c73d19b816b0979e538..725247beebecda3493e9e477f7fd4ec29911b558 100644 (file)
@@ -159,8 +159,6 @@ struct pci_dn {
 
        int     pci_ext_config_space;   /* for pci devices */
 
-       bool    force_32bit_msi;
-
        struct  pci_dev *pcidev;        /* back-pointer to the pci device */
 #ifdef CONFIG_EEH
        struct eeh_dev *edev;           /* eeh device */
index f19b1e5cb06096e2bd9b68b8cd620669c8943cac..1ceecdda810b04722b88329d52b866c3c540ad0e 100644 (file)
@@ -65,7 +65,7 @@ static ssize_t eeh_pe_state_show(struct device *dev,
                return -ENODEV;
 
        state = eeh_ops->get_state(edev->pe, NULL);
-       return sprintf(buf, "%0x08x %0x08x\n",
+       return sprintf(buf, "0x%08x 0x%08x\n",
                       state, edev->pe->state);
 }
 
index 155013da27e05cb801ba961b102d41f3edbfb48d..b15194e2c5fc55ca934dba97fe4863b2c273baa5 100644 (file)
@@ -266,13 +266,3 @@ int pcibus_to_node(struct pci_bus *bus)
 }
 EXPORT_SYMBOL(pcibus_to_node);
 #endif
-
-static void quirk_radeon_32bit_msi(struct pci_dev *dev)
-{
-       struct pci_dn *pdn = pci_get_pdn(dev);
-
-       if (pdn)
-               pdn->force_32bit_msi = true;
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x68f2, quirk_radeon_32bit_msi);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0xaa68, quirk_radeon_32bit_msi);
index 23eb9a9441bdad612481a7d1b2fcf12dd17a7ed3..c62be60c727485cce5108fcf4770b28f42129eee 100644 (file)
@@ -30,8 +30,8 @@
 V_FUNCTION_BEGIN(__kernel_getcpu)
   .cfi_startproc
        mfspr   r5,SPRN_SPRG_VDSO_READ
-       cmpdi   cr0,r3,0
-       cmpdi   cr1,r4,0
+       cmpwi   cr0,r3,0
+       cmpwi   cr1,r4,0
        clrlwi  r6,r5,16
        rlwinm  r7,r5,16,31-15,31-0
        beq     cr0,1f
index 5e1ed1575aabe23c245edcdff06433cfb0a62327..b322bfb51343f65fdfe76d265cdcb76928011d21 100644 (file)
@@ -57,7 +57,7 @@ static void print_hmi_event_info(struct OpalHMIEvent *hmi_evt)
        };
 
        /* Print things out */
-       if (hmi_evt->version != OpalHMIEvt_V1) {
+       if (hmi_evt->version < OpalHMIEvt_V1) {
                pr_err("HMI Interrupt, Unknown event version %d !\n",
                        hmi_evt->version);
                return;
index 468a0f23c7f2b5f756c1b553315793c03492c0d6..3ba435ec3dcd584e5f466b78eae18379a69d482b 100644 (file)
@@ -1509,7 +1509,6 @@ static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev,
                                  unsigned int is_64, struct msi_msg *msg)
 {
        struct pnv_ioda_pe *pe = pnv_ioda_get_pe(dev);
-       struct pci_dn *pdn = pci_get_pdn(dev);
        unsigned int xive_num = hwirq - phb->msi_base;
        __be32 data;
        int rc;
@@ -1523,7 +1522,7 @@ static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev,
                return -ENXIO;
 
        /* Force 32-bit MSI on some broken devices */
-       if (pdn && pdn->force_32bit_msi)
+       if (dev->no_64bit_msi)
                is_64 = 0;
 
        /* Assign XIVE to PE */
@@ -1997,7 +1996,7 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,
        if (is_kdump_kernel()) {
                pr_info("  Issue PHB reset ...\n");
                ioda_eeh_phb_reset(hose, EEH_RESET_FUNDAMENTAL);
-               ioda_eeh_phb_reset(hose, OPAL_DEASSERT_RESET);
+               ioda_eeh_phb_reset(hose, EEH_RESET_DEACTIVATE);
        }
 
        /* Configure M64 window */
index b2187d0068b876e6909376c81d390cbf7b8bad00..4b20f2c6b3b24ba950d3ea10014e0b1fffbfc0b6 100644 (file)
@@ -50,7 +50,6 @@ static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
 {
        struct pci_controller *hose = pci_bus_to_host(pdev->bus);
        struct pnv_phb *phb = hose->private_data;
-       struct pci_dn *pdn = pci_get_pdn(pdev);
        struct msi_desc *entry;
        struct msi_msg msg;
        int hwirq;
@@ -60,7 +59,7 @@ static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
        if (WARN_ON(!phb) || !phb->msi_bmp.bitmap)
                return -ENODEV;
 
-       if (pdn && pdn->force_32bit_msi && !phb->msi32_support)
+       if (pdev->no_64bit_msi && !phb->msi32_support)
                return -ENODEV;
 
        list_for_each_entry(entry, &pdev->msi_list, list) {
index 8ab5add4ac824f43c6a6b299b24ed15bf0deafb2..8b909e94fd9a10bbee407c2e1a04df7320e93a71 100644 (file)
@@ -420,7 +420,7 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type)
         */
 again:
        if (type == PCI_CAP_ID_MSI) {
-               if (pdn->force_32bit_msi) {
+               if (pdev->no_64bit_msi) {
                        rc = rtas_change_msi(pdn, RTAS_CHANGE_32MSI_FN, nvec);
                        if (rc < 0) {
                                /*
index de40b48b460e83a8aaec5168c8a4a1f025d8dd38..da08ed08815751cec116164e8f6d3e828bda9fd4 100644 (file)
@@ -361,7 +361,7 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev,
        cascade_data->virq = virt_msir;
        msi->cascade_array[irq_index] = cascade_data;
 
-       ret = request_irq(virt_msir, fsl_msi_cascade, 0,
+       ret = request_irq(virt_msir, fsl_msi_cascade, IRQF_NO_THREAD,
                          "fsl-msi-cascade", cascade_data);
        if (ret) {
                dev_err(&dev->dev, "failed to request_irq(%d), ret = %d\n",
index b988b5addf864a581ff8c36e177379c32ba92518..c8efbb37d6e076ab123a3d5d8066f58edd36acd8 100644 (file)
@@ -293,10 +293,10 @@ static inline void disable_surveillance(void)
        args.token = rtas_token("set-indicator");
        if (args.token == RTAS_UNKNOWN_SERVICE)
                return;
-       args.nargs = 3;
-       args.nret = 1;
+       args.nargs = cpu_to_be32(3);
+       args.nret = cpu_to_be32(1);
        args.rets = &args.args[3];
-       args.args[0] = SURVEILLANCE_TOKEN;
+       args.args[0] = cpu_to_be32(SURVEILLANCE_TOKEN);
        args.args[1] = 0;
        args.args[2] = 0;
        enter_rtas(__pa(&args));
index 5b1b52a04ad6283fb67308d9bf84b08494870140..7e064c68c5ec8a0ab538a15947d5c44b2db0a322 100644 (file)
@@ -12,6 +12,14 @@ int dma_supported(struct device *dev, u64 mask);
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
 
+static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+                                 enum dma_data_direction dir)
+{
+       /* Since dma_{alloc,free}_noncoherent() allocated coherent memory, this
+        * routine can be a nop.
+        */
+}
+
 extern struct dma_map_ops *dma_ops;
 extern struct dma_map_ops *leon_dma_ops;
 extern struct dma_map_ops pci32_dma_ops;
index ded8a6774ac99a6b9fd6708e440f66bc2f6e7433..41a503c158626a870906de36516765869c40ae1d 100644 (file)
@@ -144,7 +144,7 @@ config INSTRUCTION_DECODER
 
 config PERF_EVENTS_INTEL_UNCORE
        def_bool y
-       depends on PERF_EVENTS && SUP_SUP_INTEL && PCI
+       depends on PERF_EVENTS && CPU_SUP_INTEL && PCI
 
 config OUTPUT_FORMAT
        string
index f48b17df42249e45cca9ef6de99bfd43083507cd..3a52ee0e726d4ca2643ff6b0dec4675f39e296b5 100644 (file)
@@ -20,7 +20,6 @@
 #define THREAD_SIZE_ORDER      1
 #define THREAD_SIZE            (PAGE_SIZE << THREAD_SIZE_ORDER)
 
-#define STACKFAULT_STACK 0
 #define DOUBLEFAULT_STACK 1
 #define NMI_STACK 0
 #define DEBUG_STACK 0
index 678205195ae118e16ca34609a24f472d9875e568..75450b2c7be48393607da8a5fdf050e663eb48c8 100644 (file)
 #define IRQ_STACK_ORDER 2
 #define IRQ_STACK_SIZE (PAGE_SIZE << IRQ_STACK_ORDER)
 
-#define STACKFAULT_STACK 1
-#define DOUBLEFAULT_STACK 2
-#define NMI_STACK 3
-#define DEBUG_STACK 4
-#define MCE_STACK 5
-#define N_EXCEPTION_STACKS 5  /* hw limit: 7 */
+#define DOUBLEFAULT_STACK 1
+#define NMI_STACK 2
+#define DEBUG_STACK 3
+#define MCE_STACK 4
+#define N_EXCEPTION_STACKS 4  /* hw limit: 7 */
 
 #define PUD_PAGE_SIZE          (_AC(1, UL) << PUD_SHIFT)
 #define PUD_PAGE_MASK          (~(PUD_PAGE_SIZE-1))
index 854053889d4d2d6f74cdb3143da4f6c63e213996..547e344a6dc60d7db27d43c74d44c783326291bb 100644 (file)
@@ -141,7 +141,7 @@ struct thread_info {
 /* Only used for 64 bit */
 #define _TIF_DO_NOTIFY_MASK                                            \
        (_TIF_SIGPENDING | _TIF_MCE_NOTIFY | _TIF_NOTIFY_RESUME |       \
-        _TIF_USER_RETURN_NOTIFY)
+        _TIF_USER_RETURN_NOTIFY | _TIF_UPROBE)
 
 /* flags to check in __switch_to() */
 #define _TIF_WORK_CTXSW                                                        \
index bc8352e7010a9e805c54068da84b3848dcc12048..707adc6549d82335a20bdf18d18b697fa1fe9eab 100644 (file)
@@ -39,6 +39,7 @@ asmlinkage void simd_coprocessor_error(void);
 
 #ifdef CONFIG_TRACING
 asmlinkage void trace_page_fault(void);
+#define trace_stack_segment stack_segment
 #define trace_divide_error divide_error
 #define trace_bounds bounds
 #define trace_invalid_op invalid_op
index 4b4f78c9ba1902ed87127738052135ed54071088..cfa9b5b2c27a0b72d794f4aa048deaa404e8baef 100644 (file)
@@ -146,6 +146,8 @@ EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);
 
 static int __init x86_xsave_setup(char *s)
 {
+       if (strlen(s))
+               return 0;
        setup_clear_cpu_cap(X86_FEATURE_XSAVE);
        setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
        setup_clear_cpu_cap(X86_FEATURE_XSAVES);
index dd9d6190b08dfae5fdaee714ab5f556040af516e..2ce9051174e608381c6a91171e7e3d0d5a6a44ca 100644 (file)
@@ -465,6 +465,14 @@ static void mc_bp_resume(void)
 
        if (uci->valid && uci->mc)
                microcode_ops->apply_microcode(cpu);
+       else if (!uci->mc)
+               /*
+                * We might resume and not have applied late microcode but still
+                * have a newer patch stashed from the early loader. We don't
+                * have it in uci->mc so we have to load it the same way we're
+                * applying patches early on the APs.
+                */
+               load_ucode_ap();
 }
 
 static struct syscore_ops mc_syscore_ops = {
index adf138eac85c3384550e2f14ec5ac3377ed87000..f9ed429d6e4f83a00789ba8e5b81b704905c9764 100644 (file)
@@ -486,14 +486,17 @@ static struct attribute_group snbep_uncore_qpi_format_group = {
        .attrs = snbep_uncore_qpi_formats_attr,
 };
 
-#define SNBEP_UNCORE_MSR_OPS_COMMON_INIT()                     \
-       .init_box       = snbep_uncore_msr_init_box,            \
+#define __SNBEP_UNCORE_MSR_OPS_COMMON_INIT()                   \
        .disable_box    = snbep_uncore_msr_disable_box,         \
        .enable_box     = snbep_uncore_msr_enable_box,          \
        .disable_event  = snbep_uncore_msr_disable_event,       \
        .enable_event   = snbep_uncore_msr_enable_event,        \
        .read_counter   = uncore_msr_read_counter
 
+#define SNBEP_UNCORE_MSR_OPS_COMMON_INIT()                     \
+       __SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),                   \
+       .init_box       = snbep_uncore_msr_init_box             \
+
 static struct intel_uncore_ops snbep_uncore_msr_ops = {
        SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
 };
@@ -1919,6 +1922,30 @@ static struct intel_uncore_type hswep_uncore_cbox = {
        .format_group           = &hswep_uncore_cbox_format_group,
 };
 
+/*
+ * Write SBOX Initialization register bit by bit to avoid spurious #GPs
+ */
+static void hswep_uncore_sbox_msr_init_box(struct intel_uncore_box *box)
+{
+       unsigned msr = uncore_msr_box_ctl(box);
+
+       if (msr) {
+               u64 init = SNBEP_PMON_BOX_CTL_INT;
+               u64 flags = 0;
+               int i;
+
+               for_each_set_bit(i, (unsigned long *)&init, 64) {
+                       flags |= (1ULL << i);
+                       wrmsrl(msr, flags);
+               }
+       }
+}
+
+static struct intel_uncore_ops hswep_uncore_sbox_msr_ops = {
+       __SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+       .init_box               = hswep_uncore_sbox_msr_init_box
+};
+
 static struct attribute *hswep_uncore_sbox_formats_attr[] = {
        &format_attr_event.attr,
        &format_attr_umask.attr,
@@ -1944,7 +1971,7 @@ static struct intel_uncore_type hswep_uncore_sbox = {
        .event_mask             = HSWEP_S_MSR_PMON_RAW_EVENT_MASK,
        .box_ctl                = HSWEP_S0_MSR_PMON_BOX_CTL,
        .msr_offset             = HSWEP_SBOX_MSR_OFFSET,
-       .ops                    = &snbep_uncore_msr_ops,
+       .ops                    = &hswep_uncore_sbox_msr_ops,
        .format_group           = &hswep_uncore_sbox_format_group,
 };
 
@@ -2025,13 +2052,27 @@ static struct intel_uncore_type hswep_uncore_imc = {
        SNBEP_UNCORE_PCI_COMMON_INIT(),
 };
 
+static unsigned hswep_uncore_irp_ctrs[] = {0xa0, 0xa8, 0xb0, 0xb8};
+
+static u64 hswep_uncore_irp_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+       u64 count = 0;
+
+       pci_read_config_dword(pdev, hswep_uncore_irp_ctrs[hwc->idx], (u32 *)&count);
+       pci_read_config_dword(pdev, hswep_uncore_irp_ctrs[hwc->idx] + 4, (u32 *)&count + 1);
+
+       return count;
+}
+
 static struct intel_uncore_ops hswep_uncore_irp_ops = {
        .init_box       = snbep_uncore_pci_init_box,
        .disable_box    = snbep_uncore_pci_disable_box,
        .enable_box     = snbep_uncore_pci_enable_box,
        .disable_event  = ivbep_uncore_irp_disable_event,
        .enable_event   = ivbep_uncore_irp_enable_event,
-       .read_counter   = ivbep_uncore_irp_read_counter,
+       .read_counter   = hswep_uncore_irp_read_counter,
 };
 
 static struct intel_uncore_type hswep_uncore_irp = {
index 1abcb50b48ae042fd06c2581802af0e1af7f49d5..ff86f19b575849fca7e20a4086e09f798ae8291d 100644 (file)
@@ -24,7 +24,6 @@ static char x86_stack_ids[][8] = {
                [ DEBUG_STACK-1                 ]       = "#DB",
                [ NMI_STACK-1                   ]       = "NMI",
                [ DOUBLEFAULT_STACK-1           ]       = "#DF",
-               [ STACKFAULT_STACK-1            ]       = "#SS",
                [ MCE_STACK-1                   ]       = "#MC",
 #if DEBUG_STKSZ > EXCEPTION_STKSZ
                [ N_EXCEPTION_STACKS ...
index df088bb03fb3ffec9148c7cc44cb65ef1aa36118..c0226ab541061870bb590a9c817d0770e618697c 100644 (file)
@@ -828,9 +828,15 @@ ENTRY(native_iret)
        jnz native_irq_return_ldt
 #endif
 
+.global native_irq_return_iret
 native_irq_return_iret:
+       /*
+        * This may fault.  Non-paranoid faults on return to userspace are
+        * handled by fixup_bad_iret.  These include #SS, #GP, and #NP.
+        * Double-faults due to espfix64 are handled in do_double_fault.
+        * Other faults here are fatal.
+        */
        iretq
-       _ASM_EXTABLE(native_irq_return_iret, bad_iret)
 
 #ifdef CONFIG_X86_ESPFIX64
 native_irq_return_ldt:
@@ -858,25 +864,6 @@ native_irq_return_ldt:
        jmp native_irq_return_iret
 #endif
 
-       .section .fixup,"ax"
-bad_iret:
-       /*
-        * The iret traps when the %cs or %ss being restored is bogus.
-        * We've lost the original trap vector and error code.
-        * #GPF is the most likely one to get for an invalid selector.
-        * So pretend we completed the iret and took the #GPF in user mode.
-        *
-        * We are now running with the kernel GS after exception recovery.
-        * But error_entry expects us to have user GS to match the user %cs,
-        * so swap back.
-        */
-       pushq $0
-
-       SWAPGS
-       jmp general_protection
-
-       .previous
-
        /* edi: workmask, edx: work */
 retint_careful:
        CFI_RESTORE_STATE
@@ -922,37 +909,6 @@ ENTRY(retint_kernel)
        CFI_ENDPROC
 END(common_interrupt)
 
-       /*
-        * If IRET takes a fault on the espfix stack, then we
-        * end up promoting it to a doublefault.  In that case,
-        * modify the stack to make it look like we just entered
-        * the #GP handler from user space, similar to bad_iret.
-        */
-#ifdef CONFIG_X86_ESPFIX64
-       ALIGN
-__do_double_fault:
-       XCPT_FRAME 1 RDI+8
-       movq RSP(%rdi),%rax             /* Trap on the espfix stack? */
-       sarq $PGDIR_SHIFT,%rax
-       cmpl $ESPFIX_PGD_ENTRY,%eax
-       jne do_double_fault             /* No, just deliver the fault */
-       cmpl $__KERNEL_CS,CS(%rdi)
-       jne do_double_fault
-       movq RIP(%rdi),%rax
-       cmpq $native_irq_return_iret,%rax
-       jne do_double_fault             /* This shouldn't happen... */
-       movq PER_CPU_VAR(kernel_stack),%rax
-       subq $(6*8-KERNEL_STACK_OFFSET),%rax    /* Reset to original stack */
-       movq %rax,RSP(%rdi)
-       movq $0,(%rax)                  /* Missing (lost) #GP error code */
-       movq $general_protection,RIP(%rdi)
-       retq
-       CFI_ENDPROC
-END(__do_double_fault)
-#else
-# define __do_double_fault do_double_fault
-#endif
-
 /*
  * APIC interrupts.
  */
@@ -1124,7 +1080,7 @@ idtentry overflow do_overflow has_error_code=0
 idtentry bounds do_bounds has_error_code=0
 idtentry invalid_op do_invalid_op has_error_code=0
 idtentry device_not_available do_device_not_available has_error_code=0
-idtentry double_fault __do_double_fault has_error_code=1 paranoid=1
+idtentry double_fault do_double_fault has_error_code=1 paranoid=1
 idtentry coprocessor_segment_overrun do_coprocessor_segment_overrun has_error_code=0
 idtentry invalid_TSS do_invalid_TSS has_error_code=1
 idtentry segment_not_present do_segment_not_present has_error_code=1
@@ -1289,7 +1245,7 @@ apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \
 
 idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK
 idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK
-idtentry stack_segment do_stack_segment has_error_code=1 paranoid=1
+idtentry stack_segment do_stack_segment has_error_code=1
 #ifdef CONFIG_XEN
 idtentry xen_debug do_debug has_error_code=0
 idtentry xen_int3 do_int3 has_error_code=0
@@ -1399,17 +1355,16 @@ error_sti:
 
 /*
  * There are two places in the kernel that can potentially fault with
- * usergs. Handle them here. The exception handlers after iret run with
- * kernel gs again, so don't set the user space flag. B stepping K8s
- * sometimes report an truncated RIP for IRET exceptions returning to
- * compat mode. Check for these here too.
+ * usergs. Handle them here.  B stepping K8s sometimes report a
+ * truncated RIP for IRET exceptions returning to compat mode. Check
+ * for these here too.
  */
 error_kernelspace:
        CFI_REL_OFFSET rcx, RCX+8
        incl %ebx
        leaq native_irq_return_iret(%rip),%rcx
        cmpq %rcx,RIP+8(%rsp)
-       je error_swapgs
+       je error_bad_iret
        movl %ecx,%eax  /* zero extend */
        cmpq %rax,RIP+8(%rsp)
        je bstep_iret
@@ -1420,7 +1375,15 @@ error_kernelspace:
 bstep_iret:
        /* Fix truncated RIP */
        movq %rcx,RIP+8(%rsp)
-       jmp error_swapgs
+       /* fall through */
+
+error_bad_iret:
+       SWAPGS
+       mov %rsp,%rdi
+       call fixup_bad_iret
+       mov %rax,%rsp
+       decl %ebx       /* Return to usergs */
+       jmp error_sti
        CFI_ENDPROC
 END(error_entry)
 
index 749b0e423419fee7b97698e725dc6d665c1aa828..e510618b2e91a7969bb8cf6c74a35f59e4bf1bea 100644 (file)
@@ -1484,7 +1484,7 @@ unsigned long syscall_trace_enter_phase1(struct pt_regs *regs, u32 arch)
         */
        if (work & _TIF_NOHZ) {
                user_exit();
-               work &= ~TIF_NOHZ;
+               work &= ~_TIF_NOHZ;
        }
 
 #ifdef CONFIG_SECCOMP
index 0d0e922fafc149400b4320c793e1d311c96d147b..de801f22128a6b183aa5ab21ac3a3cd158af5610 100644 (file)
@@ -233,32 +233,40 @@ DO_ERROR(X86_TRAP_UD,     SIGILL,  "invalid opcode",              invalid_op)
 DO_ERROR(X86_TRAP_OLD_MF, SIGFPE,  "coprocessor segment overrun",coprocessor_segment_overrun)
 DO_ERROR(X86_TRAP_TS,     SIGSEGV, "invalid TSS",              invalid_TSS)
 DO_ERROR(X86_TRAP_NP,     SIGBUS,  "segment not present",      segment_not_present)
-#ifdef CONFIG_X86_32
 DO_ERROR(X86_TRAP_SS,     SIGBUS,  "stack segment",            stack_segment)
-#endif
 DO_ERROR(X86_TRAP_AC,     SIGBUS,  "alignment check",          alignment_check)
 
 #ifdef CONFIG_X86_64
 /* Runs on IST stack */
-dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
-{
-       enum ctx_state prev_state;
-
-       prev_state = exception_enter();
-       if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
-                      X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) {
-               preempt_conditional_sti(regs);
-               do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL);
-               preempt_conditional_cli(regs);
-       }
-       exception_exit(prev_state);
-}
-
 dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
 {
        static const char str[] = "double fault";
        struct task_struct *tsk = current;
 
+#ifdef CONFIG_X86_ESPFIX64
+       extern unsigned char native_irq_return_iret[];
+
+       /*
+        * If IRET takes a non-IST fault on the espfix64 stack, then we
+        * end up promoting it to a doublefault.  In that case, modify
+        * the stack to make it look like we just entered the #GP
+        * handler from user space, similar to bad_iret.
+        */
+       if (((long)regs->sp >> PGDIR_SHIFT) == ESPFIX_PGD_ENTRY &&
+               regs->cs == __KERNEL_CS &&
+               regs->ip == (unsigned long)native_irq_return_iret)
+       {
+               struct pt_regs *normal_regs = task_pt_regs(current);
+
+               /* Fake a #GP(0) from userspace. */
+               memmove(&normal_regs->ip, (void *)regs->sp, 5*8);
+               normal_regs->orig_ax = 0;  /* Missing (lost) #GP error code */
+               regs->ip = (unsigned long)general_protection;
+               regs->sp = (unsigned long)&normal_regs->orig_ax;
+               return;
+       }
+#endif
+
        exception_enter();
        /* Return not checked because double check cannot be ignored */
        notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);
@@ -399,6 +407,35 @@ asmlinkage __visible struct pt_regs *sync_regs(struct pt_regs *eregs)
        return regs;
 }
 NOKPROBE_SYMBOL(sync_regs);
+
+struct bad_iret_stack {
+       void *error_entry_ret;
+       struct pt_regs regs;
+};
+
+asmlinkage __visible
+struct bad_iret_stack *fixup_bad_iret(struct bad_iret_stack *s)
+{
+       /*
+        * This is called from entry_64.S early in handling a fault
+        * caused by a bad iret to user mode.  To handle the fault
+        * correctly, we want move our stack frame to task_pt_regs
+        * and we want to pretend that the exception came from the
+        * iret target.
+        */
+       struct bad_iret_stack *new_stack =
+               container_of(task_pt_regs(current),
+                            struct bad_iret_stack, regs);
+
+       /* Copy the IRET target to the new stack. */
+       memmove(&new_stack->regs.ip, (void *)s->regs.sp, 5*8);
+
+       /* Copy the remainder of the stack from the current stack. */
+       memmove(new_stack, s, offsetof(struct bad_iret_stack, regs.ip));
+
+       BUG_ON(!user_mode_vm(&new_stack->regs));
+       return new_stack;
+}
 #endif
 
 /*
@@ -778,7 +815,7 @@ void __init trap_init(void)
        set_intr_gate(X86_TRAP_OLD_MF, coprocessor_segment_overrun);
        set_intr_gate(X86_TRAP_TS, invalid_TSS);
        set_intr_gate(X86_TRAP_NP, segment_not_present);
-       set_intr_gate_ist(X86_TRAP_SS, &stack_segment, STACKFAULT_STACK);
+       set_intr_gate(X86_TRAP_SS, stack_segment);
        set_intr_gate(X86_TRAP_GP, general_protection);
        set_intr_gate(X86_TRAP_SPURIOUS, spurious_interrupt_bug);
        set_intr_gate(X86_TRAP_MF, coprocessor_error);
index ac1c4de3a48491d9b0cf939897e9af57238b3f71..978f402006eef21ee569720a0d573a6a48e12c97 100644 (file)
@@ -630,7 +630,7 @@ static int mmu_spte_clear_track_bits(u64 *sptep)
         * kvm mmu, before reclaiming the page, we should
         * unmap it from mmu first.
         */
-       WARN_ON(!kvm_is_mmio_pfn(pfn) && !page_count(pfn_to_page(pfn)));
+       WARN_ON(!kvm_is_reserved_pfn(pfn) && !page_count(pfn_to_page(pfn)));
 
        if (!shadow_accessed_mask || old_spte & shadow_accessed_mask)
                kvm_set_pfn_accessed(pfn);
@@ -2461,7 +2461,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
                spte |= PT_PAGE_SIZE_MASK;
        if (tdp_enabled)
                spte |= kvm_x86_ops->get_mt_mask(vcpu, gfn,
-                       kvm_is_mmio_pfn(pfn));
+                       kvm_is_reserved_pfn(pfn));
 
        if (host_writable)
                spte |= SPTE_HOST_WRITEABLE;
@@ -2737,7 +2737,7 @@ static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu,
         * PT_PAGE_TABLE_LEVEL and there would be no adjustment done
         * here.
         */
-       if (!is_error_noslot_pfn(pfn) && !kvm_is_mmio_pfn(pfn) &&
+       if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn) &&
            level == PT_PAGE_TABLE_LEVEL &&
            PageTransCompound(pfn_to_page(pfn)) &&
            !has_wrprotected_page(vcpu->kvm, gfn, PT_DIRECTORY_LEVEL)) {
index 4cb8763868fc20add0018a26df9752f1cd03937d..4e5dfec750fc9296e726a213b8e097f4f885fb70 100644 (file)
@@ -1123,7 +1123,7 @@ void mark_rodata_ro(void)
        unsigned long end = (unsigned long) &__end_rodata_hpage_align;
        unsigned long text_end = PFN_ALIGN(&__stop___ex_table);
        unsigned long rodata_end = PFN_ALIGN(&__end_rodata);
-       unsigned long all_end = PFN_ALIGN(&_end);
+       unsigned long all_end;
 
        printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n",
               (end - start) >> 10);
@@ -1134,7 +1134,16 @@ void mark_rodata_ro(void)
        /*
         * The rodata/data/bss/brk section (but not the kernel text!)
         * should also be not-executable.
+        *
+        * We align all_end to PMD_SIZE because the existing mapping
+        * is a full PMD. If we would align _brk_end to PAGE_SIZE we
+        * split the PMD and the reminder between _brk_end and the end
+        * of the PMD will remain mapped executable.
+        *
+        * Any PMD which was setup after the one which covers _brk_end
+        * has been zapped already via cleanup_highmem().
         */
+       all_end = roundup((unsigned long)_brk_end, PMD_SIZE);
        set_memory_nx(rodata_start, (all_end - rodata_start) >> PAGE_SHIFT);
 
        rodata_test();
index 0b0b124d3eced65387195f54b5d40d2dea912bbe..23210baade2d5f1e1243ededf16deeb90a174df9 100644 (file)
@@ -19,7 +19,16 @@ while (<>) {
                if ($file_offset == 0) {
                        $file_offset = $offset;
                } elsif ($file_offset != $offset) {
-                       die ".bss and .brk lack common file offset\n";
+                       # BFD linker shows the same file offset in ELF.
+                       # Gold linker shows them as consecutive.
+                       next if ($file_offset + $mem_size == $offset + $size);
+
+                       printf STDERR "file_offset: 0x%lx\n", $file_offset;
+                       printf STDERR "mem_size: 0x%lx\n", $mem_size;
+                       printf STDERR "offset: 0x%lx\n", $offset;
+                       printf STDERR "size: 0x%lx\n", $size;
+
+                       die ".bss and .brk are non-contiguous\n";
                }
        }
 }
index 143ec6ea1468109a745bce176b2f15d3aaaced19..7db19316076659b493ab1d1c9a295dc88450381d 100644 (file)
@@ -878,7 +878,7 @@ int acpi_dev_suspend_late(struct device *dev)
                return 0;
 
        target_state = acpi_target_system_state();
-       wakeup = device_may_wakeup(dev);
+       wakeup = device_may_wakeup(dev) && acpi_device_can_wakeup(adev);
        error = acpi_device_wakeup(adev, target_state, wakeup);
        if (wakeup && error)
                return error;
index 7652e8dc188f93036e03a23a99ac7aee3b543811..21b0bc6a9c969ea677630a827f69c45545a9e78a 100644 (file)
@@ -1225,11 +1225,13 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
        card->config_regs = pci_iomap(dev, 0, CONFIG_RAM_SIZE);
        if (!card->config_regs) {
                dev_warn(&dev->dev, "Failed to ioremap config registers\n");
+               err = -ENOMEM;
                goto out_release_regions;
        }
        card->buffers = pci_iomap(dev, 1, DATA_RAM_SIZE);
        if (!card->buffers) {
                dev_warn(&dev->dev, "Failed to ioremap data buffers\n");
+               err = -ENOMEM;
                goto out_unmap_config;
        }
 
index 24b5b020753a9e4a66a5d3db7c8f7ad8bee0b928..a23ac0c724f014643e66bc2485f7c79cef523920 100644 (file)
@@ -52,29 +52,26 @@ static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw,
 
        tmp = pmc_read(pmc, AT91_PMC_USB);
        usbdiv = (tmp & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT;
-       return parent_rate / (usbdiv + 1);
+
+       return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1));
 }
 
 static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
                                          unsigned long *parent_rate)
 {
        unsigned long div;
-       unsigned long bestrate;
-       unsigned long tmp;
+
+       if (!rate)
+               return -EINVAL;
 
        if (rate >= *parent_rate)
                return *parent_rate;
 
-       div = *parent_rate / rate;
-       if (div >= SAM9X5_USB_MAX_DIV)
-               return *parent_rate / (SAM9X5_USB_MAX_DIV + 1);
-
-       bestrate = *parent_rate / div;
-       tmp = *parent_rate / (div + 1);
-       if (bestrate - rate > rate - tmp)
-               bestrate = tmp;
+       div = DIV_ROUND_CLOSEST(*parent_rate, rate);
+       if (div > SAM9X5_USB_MAX_DIV + 1)
+               div = SAM9X5_USB_MAX_DIV + 1;
 
-       return bestrate;
+       return DIV_ROUND_CLOSEST(*parent_rate, div);
 }
 
 static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index)
@@ -106,9 +103,13 @@ static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
        u32 tmp;
        struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
        struct at91_pmc *pmc = usb->pmc;
-       unsigned long div = parent_rate / rate;
+       unsigned long div;
+
+       if (!rate)
+               return -EINVAL;
 
-       if (parent_rate % rate || div < 1 || div >= SAM9X5_USB_MAX_DIV)
+       div = DIV_ROUND_CLOSEST(parent_rate, rate);
+       if (div > SAM9X5_USB_MAX_DIV + 1 || !div)
                return -EINVAL;
 
        tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_OHCIUSBDIV;
@@ -253,7 +254,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
 
                tmp_parent_rate = rate * usb->divisors[i];
                tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate);
-               tmprate = tmp_parent_rate / usb->divisors[i];
+               tmprate = DIV_ROUND_CLOSEST(tmp_parent_rate, usb->divisors[i]);
                if (tmprate < rate)
                        tmpdiff = rate - tmprate;
                else
@@ -281,10 +282,10 @@ static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
        struct at91_pmc *pmc = usb->pmc;
        unsigned long div;
 
-       if (!rate || parent_rate % rate)
+       if (!rate)
                return -EINVAL;
 
-       div = parent_rate / rate;
+       div = DIV_ROUND_CLOSEST(parent_rate, rate);
 
        for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) {
                if (usb->divisors[i] == div) {
index 18a9de29df0e0c31dadd3de0b2bdb2485fab2733..c0a842b335c520c6c28f08308a1b62a743038dd3 100644 (file)
@@ -263,6 +263,14 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
        if (!rate)
                rate = 1;
 
+       /* if read only, just return current value */
+       if (divider->flags & CLK_DIVIDER_READ_ONLY) {
+               bestdiv = readl(divider->reg) >> divider->shift;
+               bestdiv &= div_mask(divider);
+               bestdiv = _get_div(divider, bestdiv);
+               return bestdiv;
+       }
+
        maxdiv = _get_maxdiv(divider);
 
        if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
@@ -361,11 +369,6 @@ const struct clk_ops clk_divider_ops = {
 };
 EXPORT_SYMBOL_GPL(clk_divider_ops);
 
-const struct clk_ops clk_divider_ro_ops = {
-       .recalc_rate = clk_divider_recalc_rate,
-};
-EXPORT_SYMBOL_GPL(clk_divider_ro_ops);
-
 static struct clk *_register_divider(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 shift, u8 width,
@@ -391,10 +394,7 @@ static struct clk *_register_divider(struct device *dev, const char *name,
        }
 
        init.name = name;
-       if (clk_divider_flags & CLK_DIVIDER_READ_ONLY)
-               init.ops = &clk_divider_ro_ops;
-       else
-               init.ops = &clk_divider_ops;
+       init.ops = &clk_divider_ops;
        init.flags = flags | CLK_IS_BASIC;
        init.parent_names = (parent_name ? &parent_name: NULL);
        init.num_parents = (parent_name ? 1 : 0);
index b345cc791e5defdeeb57d0b8df4d566bd41aef2c..88b9fe13fa444b2a81a3bd8a2588b035357d0048 100644 (file)
@@ -322,7 +322,7 @@ static unsigned long clk_pxa27x_memory_get_rate(struct clk_hw *hw,
        unsigned long ccsr = CCSR;
 
        osc_forced = ccsr & (1 << CCCR_CPDIS_BIT);
-       a = cccr & CCCR_A_BIT;
+       a = cccr & (1 << CCCR_A_BIT);
        l  = ccsr & CCSR_L_MASK;
 
        if (osc_forced || a)
@@ -341,7 +341,7 @@ static u8 clk_pxa27x_memory_get_parent(struct clk_hw *hw)
        unsigned long ccsr = CCSR;
 
        osc_forced = ccsr & (1 << CCCR_CPDIS_BIT);
-       a = cccr & CCCR_A_BIT;
+       a = cccr & (1 << CCCR_A_BIT);
        if (osc_forced)
                return PXA_MEM_13Mhz;
        if (a)
index dab988ab8cf12740ac931c5f5efaa39b90887ec3..157139a5c1ca956d76d1be30dfb6687f82d01816 100644 (file)
@@ -3122,7 +3122,7 @@ static struct clk_regmap *mmcc_apq8084_clocks[] = {
        [ESC1_CLK_SRC] = &esc1_clk_src.clkr,
        [HDMI_CLK_SRC] = &hdmi_clk_src.clkr,
        [VSYNC_CLK_SRC] = &vsync_clk_src.clkr,
-       [RBCPR_CLK_SRC] = &rbcpr_clk_src.clkr,
+       [MMSS_RBCPR_CLK_SRC] = &rbcpr_clk_src.clkr,
        [RBBMTIMER_CLK_SRC] = &rbbmtimer_clk_src.clkr,
        [MAPLE_CLK_SRC] = &maple_clk_src.clkr,
        [VDP_CLK_SRC] = &vdp_clk_src.clkr,
index 1e68bff481b8e32ec440959002a2467287c269da..880a266f01431b3b9e7040565d3a3e81f0716a8b 100644 (file)
@@ -90,9 +90,7 @@ static struct clk *rockchip_clk_register_branch(const char *name,
                div->width = div_width;
                div->lock = lock;
                div->table = div_table;
-               div_ops = (div_flags & CLK_DIVIDER_READ_ONLY)
-                                               ? &clk_divider_ro_ops
-                                               : &clk_divider_ops;
+               div_ops = &clk_divider_ops;
        }
 
        clk = clk_register_composite(NULL, name, parent_names, num_parents,
index efb17c3ee120e5ee28fa05099c4c3c7ce09f0ac1..f4a9c0058b4d677382863a12bf887b40202f63fe 100644 (file)
@@ -182,6 +182,12 @@ static void __init sun4i_timer_init(struct device_node *node)
        /* Make sure timer is stopped before playing with interrupts */
        sun4i_clkevt_time_stop(0);
 
+       sun4i_clockevent.cpumask = cpu_possible_mask;
+       sun4i_clockevent.irq = irq;
+
+       clockevents_config_and_register(&sun4i_clockevent, rate,
+                                       TIMER_SYNC_TICKS, 0xffffffff);
+
        ret = setup_irq(irq, &sun4i_timer_irq);
        if (ret)
                pr_warn("failed to setup irq %d\n", irq);
@@ -189,12 +195,6 @@ static void __init sun4i_timer_init(struct device_node *node)
        /* Enable timer0 interrupt */
        val = readl(timer_base + TIMER_IRQ_EN_REG);
        writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG);
-
-       sun4i_clockevent.cpumask = cpu_possible_mask;
-       sun4i_clockevent.irq = irq;
-
-       clockevents_config_and_register(&sun4i_clockevent, rate,
-                                       TIMER_SYNC_TICKS, 0xffffffff);
 }
 CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer",
                       sun4i_timer_init);
index 4839bfa74a107a1ad4cbdfb09017d86da1fd1a41..19a99743cf524670d5906400d286cc877bcf91d6 100644 (file)
@@ -271,7 +271,7 @@ struct pl330_config {
 #define DMAC_MODE_NS   (1 << 0)
        unsigned int    mode;
        unsigned int    data_bus_width:10; /* In number of bits */
-       unsigned int    data_buf_dep:10;
+       unsigned int    data_buf_dep:11;
        unsigned int    num_chan:4;
        unsigned int    num_peri:6;
        u32             peri_ns;
@@ -2336,7 +2336,7 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len)
        int burst_len;
 
        burst_len = pl330->pcfg.data_bus_width / 8;
-       burst_len *= pl330->pcfg.data_buf_dep;
+       burst_len *= pl330->pcfg.data_buf_dep / pl330->pcfg.num_chan;
        burst_len >>= desc->rqcfg.brst_size;
 
        /* src/dst_burst_len can't be more than 16 */
@@ -2459,16 +2459,25 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
        /* Select max possible burst size */
        burst = pl330->pcfg.data_bus_width / 8;
 
-       while (burst > 1) {
-               if (!(len % burst))
-                       break;
+       /*
+        * Make sure we use a burst size that aligns with all the memcpy
+        * parameters because our DMA programming algorithm doesn't cope with
+        * transfers which straddle an entry in the DMA device's MFIFO.
+        */
+       while ((src | dst | len) & (burst - 1))
                burst /= 2;
-       }
 
        desc->rqcfg.brst_size = 0;
        while (burst != (1 << desc->rqcfg.brst_size))
                desc->rqcfg.brst_size++;
 
+       /*
+        * If burst size is smaller than bus width then make sure we only
+        * transfer one at a time to avoid a burst stradling an MFIFO entry.
+        */
+       if (desc->rqcfg.brst_size * 8 < pl330->pcfg.data_bus_width)
+               desc->rqcfg.brst_len = 1;
+
        desc->rqcfg.brst_len = get_burst_len(desc, len);
 
        desc->txd.flags = flags;
@@ -2732,7 +2741,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 
 
        dev_info(&adev->dev,
-               "Loaded driver for PL330 DMAC-%d\n", adev->periphid);
+               "Loaded driver for PL330 DMAC-%x\n", adev->periphid);
        dev_info(&adev->dev,
                "\tDBUFF-%ux%ubytes Num_Chans-%u Num_Peri-%u Num_Events-%u\n",
                pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan,
index 3aa10b32825491dce9d5c0ad244ddc53f78df12e..91292f5513ff2df6d051b784fcb81d276f6e6c63 100644 (file)
@@ -230,30 +230,25 @@ static inline void sun6i_dma_dump_chan_regs(struct sun6i_dma_dev *sdev,
                readl(pchan->base + DMA_CHAN_CUR_PARA));
 }
 
-static inline int convert_burst(u32 maxburst, u8 *burst)
+static inline s8 convert_burst(u32 maxburst)
 {
        switch (maxburst) {
        case 1:
-               *burst = 0;
-               break;
+               return 0;
        case 8:
-               *burst = 2;
-               break;
+               return 2;
        default:
                return -EINVAL;
        }
-
-       return 0;
 }
 
-static inline int convert_buswidth(enum dma_slave_buswidth addr_width, u8 *width)
+static inline s8 convert_buswidth(enum dma_slave_buswidth addr_width)
 {
        if ((addr_width < DMA_SLAVE_BUSWIDTH_1_BYTE) ||
            (addr_width > DMA_SLAVE_BUSWIDTH_4_BYTES))
                return -EINVAL;
 
-       *width = addr_width >> 1;
-       return 0;
+       return addr_width >> 1;
 }
 
 static void *sun6i_dma_lli_add(struct sun6i_dma_lli *prev,
@@ -284,26 +279,25 @@ static inline int sun6i_dma_cfg_lli(struct sun6i_dma_lli *lli,
                                    struct dma_slave_config *config)
 {
        u8 src_width, dst_width, src_burst, dst_burst;
-       int ret;
 
        if (!config)
                return -EINVAL;
 
-       ret = convert_burst(config->src_maxburst, &src_burst);
-       if (ret)
-               return ret;
+       src_burst = convert_burst(config->src_maxburst);
+       if (src_burst)
+               return src_burst;
 
-       ret = convert_burst(config->dst_maxburst, &dst_burst);
-       if (ret)
-               return ret;
+       dst_burst = convert_burst(config->dst_maxburst);
+       if (dst_burst)
+               return dst_burst;
 
-       ret = convert_buswidth(config->src_addr_width, &src_width);
-       if (ret)
-               return ret;
+       src_width = convert_buswidth(config->src_addr_width);
+       if (src_width)
+               return src_width;
 
-       ret = convert_buswidth(config->dst_addr_width, &dst_width);
-       if (ret)
-               return ret;
+       dst_width = convert_buswidth(config->dst_addr_width);
+       if (dst_width)
+               return dst_width;
 
        lli->cfg = DMA_CHAN_CFG_SRC_BURST(src_burst) |
                DMA_CHAN_CFG_SRC_WIDTH(src_width) |
@@ -542,11 +536,10 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
 {
        struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
        struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
-       struct dma_slave_config *sconfig = &vchan->cfg;
        struct sun6i_dma_lli *v_lli;
        struct sun6i_desc *txd;
        dma_addr_t p_lli;
-       int ret;
+       s8 burst, width;
 
        dev_dbg(chan2dev(chan),
                "%s; chan: %d, dest: %pad, src: %pad, len: %zu. flags: 0x%08lx\n",
@@ -565,14 +558,21 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
                goto err_txd_free;
        }
 
-       ret = sun6i_dma_cfg_lli(v_lli, src, dest, len, sconfig);
-       if (ret)
-               goto err_dma_free;
+       v_lli->src = src;
+       v_lli->dst = dest;
+       v_lli->len = len;
+       v_lli->para = NORMAL_WAIT;
 
+       burst = convert_burst(8);
+       width = convert_buswidth(DMA_SLAVE_BUSWIDTH_4_BYTES);
        v_lli->cfg |= DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) |
                DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) |
                DMA_CHAN_CFG_DST_LINEAR_MODE |
-               DMA_CHAN_CFG_SRC_LINEAR_MODE;
+               DMA_CHAN_CFG_SRC_LINEAR_MODE |
+               DMA_CHAN_CFG_SRC_BURST(burst) |
+               DMA_CHAN_CFG_SRC_WIDTH(width) |
+               DMA_CHAN_CFG_DST_BURST(burst) |
+               DMA_CHAN_CFG_DST_WIDTH(width);
 
        sun6i_dma_lli_add(NULL, v_lli, p_lli, txd);
 
@@ -580,8 +580,6 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
 
        return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
 
-err_dma_free:
-       dma_pool_free(sdev->pool, v_lli, p_lli);
 err_txd_free:
        kfree(txd);
        return NULL;
@@ -915,6 +913,7 @@ static int sun6i_dma_probe(struct platform_device *pdev)
        sdc->slave.device_prep_dma_memcpy       = sun6i_dma_prep_dma_memcpy;
        sdc->slave.device_control               = sun6i_dma_control;
        sdc->slave.chancnt                      = NR_MAX_VCHANS;
+       sdc->slave.copy_align                   = 4;
 
        sdc->slave.dev = &pdev->dev;
 
index e3b4b0f02b3d1de3e07a9d40cb11b22d1822701f..24c2d7caedd5633e3cd73712478c3f18d48c3ace 100644 (file)
@@ -200,3 +200,7 @@ source "drivers/gpu/drm/tegra/Kconfig"
 source "drivers/gpu/drm/panel/Kconfig"
 
 source "drivers/gpu/drm/sti/Kconfig"
+
+source "drivers/gpu/drm/amd/amdkfd/Kconfig"
+
+source "drivers/gpu/drm/imx/Kconfig"
index c3cf64ce28919e8cef44cb05c4578b079cf08aca..47d89869c5df01a06e91b50bea4b48eecc1c8f97 100644 (file)
@@ -62,6 +62,8 @@ obj-$(CONFIG_DRM_BOCHS) += bochs/
 obj-$(CONFIG_DRM_MSM) += msm/
 obj-$(CONFIG_DRM_TEGRA) += tegra/
 obj-$(CONFIG_DRM_STI) += sti/
+obj-$(CONFIG_DRM_IMX) += imx/
 obj-y                  += i2c/
 obj-y                  += panel/
 obj-y                  += bridge/
+obj-$(CONFIG_HSA_AMD) += amd/amdkfd/
diff --git a/drivers/gpu/drm/amd/amdkfd/Kconfig b/drivers/gpu/drm/amd/amdkfd/Kconfig
new file mode 100644 (file)
index 0000000..8dfac37
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Heterogenous system architecture configuration
+#
+
+config HSA_AMD
+       tristate "HSA kernel driver for AMD GPU devices"
+       depends on DRM_RADEON && AMD_IOMMU_V2 && X86_64
+       help
+         Enable this if you want to use HSA features on AMD GPU devices.
diff --git a/drivers/gpu/drm/amd/amdkfd/Makefile b/drivers/gpu/drm/amd/amdkfd/Makefile
new file mode 100644 (file)
index 0000000..be6246d
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Makefile for Heterogenous System Architecture support for AMD GPU devices
+#
+
+ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include/
+
+amdkfd-y       := kfd_module.o kfd_device.o kfd_chardev.o kfd_topology.o \
+               kfd_pasid.o kfd_doorbell.o kfd_flat_memory.o \
+               kfd_process.o kfd_queue.o kfd_mqd_manager.o \
+               kfd_kernel_queue.o kfd_packet_manager.o \
+               kfd_process_queue_manager.o kfd_device_queue_manager.o \
+               kfd_interrupt.o
+
+obj-$(CONFIG_HSA_AMD)  += amdkfd.o
diff --git a/drivers/gpu/drm/amd/amdkfd/cik_regs.h b/drivers/gpu/drm/amd/amdkfd/cik_regs.h
new file mode 100644 (file)
index 0000000..607fc5c
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef CIK_REGS_H
+#define CIK_REGS_H
+
+#define IH_VMID_0_LUT                                  0x3D40u
+
+#define BIF_DOORBELL_CNTL                              0x530Cu
+
+#define        SRBM_GFX_CNTL                                   0xE44
+#define        PIPEID(x)                                       ((x) << 0)
+#define        MEID(x)                                         ((x) << 2)
+#define        VMID(x)                                         ((x) << 4)
+#define        QUEUEID(x)                                      ((x) << 8)
+
+#define        SQ_CONFIG                                       0x8C00
+
+#define        SH_MEM_BASES                                    0x8C28
+/* if PTR32, these are the bases for scratch and lds */
+#define        PRIVATE_BASE(x)                                 ((x) << 0) /* scratch */
+#define        SHARED_BASE(x)                                  ((x) << 16) /* LDS */
+#define        SH_MEM_APE1_BASE                                0x8C2C
+/* if PTR32, this is the base location of GPUVM */
+#define        SH_MEM_APE1_LIMIT                               0x8C30
+/* if PTR32, this is the upper limit of GPUVM */
+#define        SH_MEM_CONFIG                                   0x8C34
+#define        PTR32                                           (1 << 0)
+#define PRIVATE_ATC                                    (1 << 1)
+#define        ALIGNMENT_MODE(x)                               ((x) << 2)
+#define        SH_MEM_ALIGNMENT_MODE_DWORD                     0
+#define        SH_MEM_ALIGNMENT_MODE_DWORD_STRICT              1
+#define        SH_MEM_ALIGNMENT_MODE_STRICT                    2
+#define        SH_MEM_ALIGNMENT_MODE_UNALIGNED                 3
+#define        DEFAULT_MTYPE(x)                                ((x) << 4)
+#define        APE1_MTYPE(x)                                   ((x) << 7)
+
+/* valid for both DEFAULT_MTYPE and APE1_MTYPE */
+#define        MTYPE_CACHED                                    0
+#define        MTYPE_NONCACHED                                 3
+
+
+#define SH_STATIC_MEM_CONFIG                           0x9604u
+
+#define        TC_CFG_L1_LOAD_POLICY0                          0xAC68
+#define        TC_CFG_L1_LOAD_POLICY1                          0xAC6C
+#define        TC_CFG_L1_STORE_POLICY                          0xAC70
+#define        TC_CFG_L2_LOAD_POLICY0                          0xAC74
+#define        TC_CFG_L2_LOAD_POLICY1                          0xAC78
+#define        TC_CFG_L2_STORE_POLICY0                         0xAC7C
+#define        TC_CFG_L2_STORE_POLICY1                         0xAC80
+#define        TC_CFG_L2_ATOMIC_POLICY                         0xAC84
+#define        TC_CFG_L1_VOLATILE                              0xAC88
+#define        TC_CFG_L2_VOLATILE                              0xAC8C
+
+#define CP_PQ_WPTR_POLL_CNTL                           0xC20C
+#define        WPTR_POLL_EN                                    (1 << 31)
+
+#define CPC_INT_CNTL                                   0xC2D0
+#define CP_ME1_PIPE0_INT_CNTL                          0xC214
+#define CP_ME1_PIPE1_INT_CNTL                          0xC218
+#define CP_ME1_PIPE2_INT_CNTL                          0xC21C
+#define CP_ME1_PIPE3_INT_CNTL                          0xC220
+#define CP_ME2_PIPE0_INT_CNTL                          0xC224
+#define CP_ME2_PIPE1_INT_CNTL                          0xC228
+#define CP_ME2_PIPE2_INT_CNTL                          0xC22C
+#define CP_ME2_PIPE3_INT_CNTL                          0xC230
+#define DEQUEUE_REQUEST_INT_ENABLE                     (1 << 13)
+#define WRM_POLL_TIMEOUT_INT_ENABLE                    (1 << 17)
+#define PRIV_REG_INT_ENABLE                            (1 << 23)
+#define TIME_STAMP_INT_ENABLE                          (1 << 26)
+#define GENERIC2_INT_ENABLE                            (1 << 29)
+#define GENERIC1_INT_ENABLE                            (1 << 30)
+#define GENERIC0_INT_ENABLE                            (1 << 31)
+#define CP_ME1_PIPE0_INT_STATUS                                0xC214
+#define CP_ME1_PIPE1_INT_STATUS                                0xC218
+#define CP_ME1_PIPE2_INT_STATUS                                0xC21C
+#define CP_ME1_PIPE3_INT_STATUS                                0xC220
+#define CP_ME2_PIPE0_INT_STATUS                                0xC224
+#define CP_ME2_PIPE1_INT_STATUS                                0xC228
+#define CP_ME2_PIPE2_INT_STATUS                                0xC22C
+#define CP_ME2_PIPE3_INT_STATUS                                0xC230
+#define DEQUEUE_REQUEST_INT_STATUS                     (1 << 13)
+#define WRM_POLL_TIMEOUT_INT_STATUS                    (1 << 17)
+#define PRIV_REG_INT_STATUS                            (1 << 23)
+#define TIME_STAMP_INT_STATUS                          (1 << 26)
+#define GENERIC2_INT_STATUS                            (1 << 29)
+#define GENERIC1_INT_STATUS                            (1 << 30)
+#define GENERIC0_INT_STATUS                            (1 << 31)
+
+#define CP_HPD_EOP_BASE_ADDR                           0xC904
+#define CP_HPD_EOP_BASE_ADDR_HI                                0xC908
+#define CP_HPD_EOP_VMID                                        0xC90C
+#define CP_HPD_EOP_CONTROL                             0xC910
+#define        EOP_SIZE(x)                                     ((x) << 0)
+#define        EOP_SIZE_MASK                                   (0x3f << 0)
+#define CP_MQD_BASE_ADDR                               0xC914
+#define CP_MQD_BASE_ADDR_HI                            0xC918
+#define CP_HQD_ACTIVE                                  0xC91C
+#define CP_HQD_VMID                                    0xC920
+
+#define CP_HQD_PERSISTENT_STATE                                0xC924u
+#define        DEFAULT_CP_HQD_PERSISTENT_STATE                 (0x33U << 8)
+#define        PRELOAD_REQ                                     (1 << 0)
+
+#define CP_HQD_PIPE_PRIORITY                           0xC928u
+#define CP_HQD_QUEUE_PRIORITY                          0xC92Cu
+#define CP_HQD_QUANTUM                                 0xC930u
+#define        QUANTUM_EN                                      1U
+#define        QUANTUM_SCALE_1MS                               (1U << 4)
+#define        QUANTUM_DURATION(x)                             ((x) << 8)
+
+#define CP_HQD_PQ_BASE                                 0xC934
+#define CP_HQD_PQ_BASE_HI                              0xC938
+#define CP_HQD_PQ_RPTR                                 0xC93C
+#define CP_HQD_PQ_RPTR_REPORT_ADDR                     0xC940
+#define CP_HQD_PQ_RPTR_REPORT_ADDR_HI                  0xC944
+#define CP_HQD_PQ_WPTR_POLL_ADDR                       0xC948
+#define CP_HQD_PQ_WPTR_POLL_ADDR_HI                    0xC94C
+#define CP_HQD_PQ_DOORBELL_CONTROL                     0xC950
+#define        DOORBELL_OFFSET(x)                              ((x) << 2)
+#define        DOORBELL_OFFSET_MASK                            (0x1fffff << 2)
+#define        DOORBELL_SOURCE                                 (1 << 28)
+#define        DOORBELL_SCHD_HIT                               (1 << 29)
+#define        DOORBELL_EN                                     (1 << 30)
+#define        DOORBELL_HIT                                    (1 << 31)
+#define CP_HQD_PQ_WPTR                                 0xC954
+#define CP_HQD_PQ_CONTROL                              0xC958
+#define        QUEUE_SIZE(x)                                   ((x) << 0)
+#define        QUEUE_SIZE_MASK                                 (0x3f << 0)
+#define        RPTR_BLOCK_SIZE(x)                              ((x) << 8)
+#define        RPTR_BLOCK_SIZE_MASK                            (0x3f << 8)
+#define        MIN_AVAIL_SIZE(x)                               ((x) << 20)
+#define        PQ_ATC_EN                                       (1 << 23)
+#define        PQ_VOLATILE                                     (1 << 26)
+#define        NO_UPDATE_RPTR                                  (1 << 27)
+#define        UNORD_DISPATCH                                  (1 << 28)
+#define        ROQ_PQ_IB_FLIP                                  (1 << 29)
+#define        PRIV_STATE                                      (1 << 30)
+#define        KMD_QUEUE                                       (1 << 31)
+
+#define        DEFAULT_RPTR_BLOCK_SIZE                         RPTR_BLOCK_SIZE(5)
+#define        DEFAULT_MIN_AVAIL_SIZE                          MIN_AVAIL_SIZE(3)
+
+#define CP_HQD_IB_BASE_ADDR                            0xC95Cu
+#define CP_HQD_IB_BASE_ADDR_HI                         0xC960u
+#define CP_HQD_IB_RPTR                                 0xC964u
+#define CP_HQD_IB_CONTROL                              0xC968u
+#define        IB_ATC_EN                                       (1U << 23)
+#define        DEFAULT_MIN_IB_AVAIL_SIZE                       (3U << 20)
+
+#define CP_HQD_DEQUEUE_REQUEST                         0xC974
+#define        DEQUEUE_REQUEST_DRAIN                           1
+#define DEQUEUE_REQUEST_RESET                          2
+#define                DEQUEUE_INT                                     (1U << 8)
+
+#define CP_HQD_SEMA_CMD                                        0xC97Cu
+#define CP_HQD_MSG_TYPE                                        0xC980u
+#define CP_HQD_ATOMIC0_PREOP_LO                                0xC984u
+#define CP_HQD_ATOMIC0_PREOP_HI                                0xC988u
+#define CP_HQD_ATOMIC1_PREOP_LO                                0xC98Cu
+#define CP_HQD_ATOMIC1_PREOP_HI                                0xC990u
+#define CP_HQD_HQ_SCHEDULER0                           0xC994u
+#define CP_HQD_HQ_SCHEDULER1                           0xC998u
+
+
+#define CP_MQD_CONTROL                                 0xC99C
+#define        MQD_VMID(x)                                     ((x) << 0)
+#define        MQD_VMID_MASK                                   (0xf << 0)
+#define        MQD_CONTROL_PRIV_STATE_EN                       (1U << 8)
+
+#define GRBM_GFX_INDEX                                 0x30800
+#define        INSTANCE_INDEX(x)                               ((x) << 0)
+#define        SH_INDEX(x)                                     ((x) << 8)
+#define        SE_INDEX(x)                                     ((x) << 16)
+#define        SH_BROADCAST_WRITES                             (1 << 29)
+#define        INSTANCE_BROADCAST_WRITES                       (1 << 30)
+#define        SE_BROADCAST_WRITES                             (1 << 31)
+
+#define SQC_CACHES                                     0x30d20
+#define SQC_POLICY                                     0x8C38u
+#define SQC_VOLATILE                                   0x8C3Cu
+
+#define CP_PERFMON_CNTL                                        0x36020
+
+#define ATC_VMID0_PASID_MAPPING                                0x339Cu
+#define        ATC_VMID_PASID_MAPPING_UPDATE_STATUS            0x3398u
+#define        ATC_VMID_PASID_MAPPING_VALID                    (1U << 31)
+
+#define ATC_VM_APERTURE0_CNTL                          0x3310u
+#define        ATS_ACCESS_MODE_NEVER                           0
+#define        ATS_ACCESS_MODE_ALWAYS                          1
+
+#define ATC_VM_APERTURE0_CNTL2                         0x3318u
+#define ATC_VM_APERTURE0_HIGH_ADDR                     0x3308u
+#define ATC_VM_APERTURE0_LOW_ADDR                      0x3300u
+#define ATC_VM_APERTURE1_CNTL                          0x3314u
+#define ATC_VM_APERTURE1_CNTL2                         0x331Cu
+#define ATC_VM_APERTURE1_HIGH_ADDR                     0x330Cu
+#define ATC_VM_APERTURE1_LOW_ADDR                      0x3304u
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
new file mode 100644 (file)
index 0000000..102cd36
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/compat.h>
+#include <uapi/linux/kfd_ioctl.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <uapi/asm-generic/mman-common.h>
+#include <asm/processor.h>
+#include "kfd_priv.h"
+#include "kfd_device_queue_manager.h"
+
+static long kfd_ioctl(struct file *, unsigned int, unsigned long);
+static int kfd_open(struct inode *, struct file *);
+static int kfd_mmap(struct file *, struct vm_area_struct *);
+
+static const char kfd_dev_name[] = "kfd";
+
+static const struct file_operations kfd_fops = {
+       .owner = THIS_MODULE,
+       .unlocked_ioctl = kfd_ioctl,
+       .compat_ioctl = kfd_ioctl,
+       .open = kfd_open,
+       .mmap = kfd_mmap,
+};
+
+static int kfd_char_dev_major = -1;
+static struct class *kfd_class;
+struct device *kfd_device;
+
+int kfd_chardev_init(void)
+{
+       int err = 0;
+
+       kfd_char_dev_major = register_chrdev(0, kfd_dev_name, &kfd_fops);
+       err = kfd_char_dev_major;
+       if (err < 0)
+               goto err_register_chrdev;
+
+       kfd_class = class_create(THIS_MODULE, kfd_dev_name);
+       err = PTR_ERR(kfd_class);
+       if (IS_ERR(kfd_class))
+               goto err_class_create;
+
+       kfd_device = device_create(kfd_class, NULL,
+                                       MKDEV(kfd_char_dev_major, 0),
+                                       NULL, kfd_dev_name);
+       err = PTR_ERR(kfd_device);
+       if (IS_ERR(kfd_device))
+               goto err_device_create;
+
+       return 0;
+
+err_device_create:
+       class_destroy(kfd_class);
+err_class_create:
+       unregister_chrdev(kfd_char_dev_major, kfd_dev_name);
+err_register_chrdev:
+       return err;
+}
+
+void kfd_chardev_exit(void)
+{
+       device_destroy(kfd_class, MKDEV(kfd_char_dev_major, 0));
+       class_destroy(kfd_class);
+       unregister_chrdev(kfd_char_dev_major, kfd_dev_name);
+}
+
+struct device *kfd_chardev(void)
+{
+       return kfd_device;
+}
+
+
+static int kfd_open(struct inode *inode, struct file *filep)
+{
+       struct kfd_process *process;
+
+       if (iminor(inode) != 0)
+               return -ENODEV;
+
+       process = kfd_create_process(current);
+       if (IS_ERR(process))
+               return PTR_ERR(process);
+
+       process->is_32bit_user_mode = is_compat_task();
+
+       dev_dbg(kfd_device, "process %d opened, compat mode (32 bit) - %d\n",
+               process->pasid, process->is_32bit_user_mode);
+
+       kfd_init_apertures(process);
+
+       return 0;
+}
+
+static long kfd_ioctl_get_version(struct file *filep, struct kfd_process *p,
+                                       void __user *arg)
+{
+       struct kfd_ioctl_get_version_args args;
+       int err = 0;
+
+       args.major_version = KFD_IOCTL_MAJOR_VERSION;
+       args.minor_version = KFD_IOCTL_MINOR_VERSION;
+
+       if (copy_to_user(arg, &args, sizeof(args)))
+               err = -EFAULT;
+
+       return err;
+}
+
+static int set_queue_properties_from_user(struct queue_properties *q_properties,
+                               struct kfd_ioctl_create_queue_args *args)
+{
+       if (args->queue_percentage > KFD_MAX_QUEUE_PERCENTAGE) {
+               pr_err("kfd: queue percentage must be between 0 to KFD_MAX_QUEUE_PERCENTAGE\n");
+               return -EINVAL;
+       }
+
+       if (args->queue_priority > KFD_MAX_QUEUE_PRIORITY) {
+               pr_err("kfd: queue priority must be between 0 to KFD_MAX_QUEUE_PRIORITY\n");
+               return -EINVAL;
+       }
+
+       if ((args->ring_base_address) &&
+               (!access_ok(VERIFY_WRITE,
+                       (const void __user *) args->ring_base_address,
+                       sizeof(uint64_t)))) {
+               pr_err("kfd: can't access ring base address\n");
+               return -EFAULT;
+       }
+
+       if (!is_power_of_2(args->ring_size) && (args->ring_size != 0)) {
+               pr_err("kfd: ring size must be a power of 2 or 0\n");
+               return -EINVAL;
+       }
+
+       if (!access_ok(VERIFY_WRITE,
+                       (const void __user *) args->read_pointer_address,
+                       sizeof(uint32_t))) {
+               pr_err("kfd: can't access read pointer\n");
+               return -EFAULT;
+       }
+
+       if (!access_ok(VERIFY_WRITE,
+                       (const void __user *) args->write_pointer_address,
+                       sizeof(uint32_t))) {
+               pr_err("kfd: can't access write pointer\n");
+               return -EFAULT;
+       }
+
+       q_properties->is_interop = false;
+       q_properties->queue_percent = args->queue_percentage;
+       q_properties->priority = args->queue_priority;
+       q_properties->queue_address = args->ring_base_address;
+       q_properties->queue_size = args->ring_size;
+       q_properties->read_ptr = (uint32_t *) args->read_pointer_address;
+       q_properties->write_ptr = (uint32_t *) args->write_pointer_address;
+       if (args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE ||
+               args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE_AQL)
+               q_properties->type = KFD_QUEUE_TYPE_COMPUTE;
+       else
+               return -ENOTSUPP;
+
+       if (args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE_AQL)
+               q_properties->format = KFD_QUEUE_FORMAT_AQL;
+       else
+               q_properties->format = KFD_QUEUE_FORMAT_PM4;
+
+       pr_debug("Queue Percentage (%d, %d)\n",
+                       q_properties->queue_percent, args->queue_percentage);
+
+       pr_debug("Queue Priority (%d, %d)\n",
+                       q_properties->priority, args->queue_priority);
+
+       pr_debug("Queue Address (0x%llX, 0x%llX)\n",
+                       q_properties->queue_address, args->ring_base_address);
+
+       pr_debug("Queue Size (0x%llX, %u)\n",
+                       q_properties->queue_size, args->ring_size);
+
+       pr_debug("Queue r/w Pointers (0x%llX, 0x%llX)\n",
+                       (uint64_t) q_properties->read_ptr,
+                       (uint64_t) q_properties->write_ptr);
+
+       pr_debug("Queue Format (%d)\n", q_properties->format);
+
+       return 0;
+}
+
+static long kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p,
+                                       void __user *arg)
+{
+       struct kfd_ioctl_create_queue_args args;
+       struct kfd_dev *dev;
+       int err = 0;
+       unsigned int queue_id;
+       struct kfd_process_device *pdd;
+       struct queue_properties q_properties;
+
+       memset(&q_properties, 0, sizeof(struct queue_properties));
+
+       if (copy_from_user(&args, arg, sizeof(args)))
+               return -EFAULT;
+
+       pr_debug("kfd: creating queue ioctl\n");
+
+       err = set_queue_properties_from_user(&q_properties, &args);
+       if (err)
+               return err;
+
+       dev = kfd_device_by_id(args.gpu_id);
+       if (dev == NULL)
+               return -EINVAL;
+
+       mutex_lock(&p->mutex);
+
+       pdd = kfd_bind_process_to_device(dev, p);
+       if (IS_ERR(pdd)) {
+               err = PTR_ERR(pdd);
+               goto err_bind_process;
+       }
+
+       pr_debug("kfd: creating queue for PASID %d on GPU 0x%x\n",
+                       p->pasid,
+                       dev->id);
+
+       err = pqm_create_queue(&p->pqm, dev, filep, &q_properties, 0,
+                               KFD_QUEUE_TYPE_COMPUTE, &queue_id);
+       if (err != 0)
+               goto err_create_queue;
+
+       args.queue_id = queue_id;
+
+       /* Return gpu_id as doorbell offset for mmap usage */
+       args.doorbell_offset = args.gpu_id << PAGE_SHIFT;
+
+       if (copy_to_user(arg, &args, sizeof(args))) {
+               err = -EFAULT;
+               goto err_copy_args_out;
+       }
+
+       mutex_unlock(&p->mutex);
+
+       pr_debug("kfd: queue id %d was created successfully\n", args.queue_id);
+
+       pr_debug("ring buffer address == 0x%016llX\n",
+                       args.ring_base_address);
+
+       pr_debug("read ptr address    == 0x%016llX\n",
+                       args.read_pointer_address);
+
+       pr_debug("write ptr address   == 0x%016llX\n",
+                       args.write_pointer_address);
+
+       return 0;
+
+err_copy_args_out:
+       pqm_destroy_queue(&p->pqm, queue_id);
+err_create_queue:
+err_bind_process:
+       mutex_unlock(&p->mutex);
+       return err;
+}
+
+static int kfd_ioctl_destroy_queue(struct file *filp, struct kfd_process *p,
+                                       void __user *arg)
+{
+       int retval;
+       struct kfd_ioctl_destroy_queue_args args;
+
+       if (copy_from_user(&args, arg, sizeof(args)))
+               return -EFAULT;
+
+       pr_debug("kfd: destroying queue id %d for PASID %d\n",
+                               args.queue_id,
+                               p->pasid);
+
+       mutex_lock(&p->mutex);
+
+       retval = pqm_destroy_queue(&p->pqm, args.queue_id);
+
+       mutex_unlock(&p->mutex);
+       return retval;
+}
+
+static int kfd_ioctl_update_queue(struct file *filp, struct kfd_process *p,
+                                       void __user *arg)
+{
+       int retval;
+       struct kfd_ioctl_update_queue_args args;
+       struct queue_properties properties;
+
+       if (copy_from_user(&args, arg, sizeof(args)))
+               return -EFAULT;
+
+       if (args.queue_percentage > KFD_MAX_QUEUE_PERCENTAGE) {
+               pr_err("kfd: queue percentage must be between 0 to KFD_MAX_QUEUE_PERCENTAGE\n");
+               return -EINVAL;
+       }
+
+       if (args.queue_priority > KFD_MAX_QUEUE_PRIORITY) {
+               pr_err("kfd: queue priority must be between 0 to KFD_MAX_QUEUE_PRIORITY\n");
+               return -EINVAL;
+       }
+
+       if ((args.ring_base_address) &&
+               (!access_ok(VERIFY_WRITE,
+                       (const void __user *) args.ring_base_address,
+                       sizeof(uint64_t)))) {
+               pr_err("kfd: can't access ring base address\n");
+               return -EFAULT;
+       }
+
+       if (!is_power_of_2(args.ring_size) && (args.ring_size != 0)) {
+               pr_err("kfd: ring size must be a power of 2 or 0\n");
+               return -EINVAL;
+       }
+
+       properties.queue_address = args.ring_base_address;
+       properties.queue_size = args.ring_size;
+       properties.queue_percent = args.queue_percentage;
+       properties.priority = args.queue_priority;
+
+       pr_debug("kfd: updating queue id %d for PASID %d\n",
+                       args.queue_id, p->pasid);
+
+       mutex_lock(&p->mutex);
+
+       retval = pqm_update_queue(&p->pqm, args.queue_id, &properties);
+
+       mutex_unlock(&p->mutex);
+
+       return retval;
+}
+
+static long kfd_ioctl_set_memory_policy(struct file *filep,
+                               struct kfd_process *p, void __user *arg)
+{
+       struct kfd_ioctl_set_memory_policy_args args;
+       struct kfd_dev *dev;
+       int err = 0;
+       struct kfd_process_device *pdd;
+       enum cache_policy default_policy, alternate_policy;
+
+       if (copy_from_user(&args, arg, sizeof(args)))
+               return -EFAULT;
+
+       if (args.default_policy != KFD_IOC_CACHE_POLICY_COHERENT
+           && args.default_policy != KFD_IOC_CACHE_POLICY_NONCOHERENT) {
+               return -EINVAL;
+       }
+
+       if (args.alternate_policy != KFD_IOC_CACHE_POLICY_COHERENT
+           && args.alternate_policy != KFD_IOC_CACHE_POLICY_NONCOHERENT) {
+               return -EINVAL;
+       }
+
+       dev = kfd_device_by_id(args.gpu_id);
+       if (dev == NULL)
+               return -EINVAL;
+
+       mutex_lock(&p->mutex);
+
+       pdd = kfd_bind_process_to_device(dev, p);
+       if (IS_ERR(pdd)) {
+               err = PTR_ERR(pdd);
+               goto out;
+       }
+
+       default_policy = (args.default_policy == KFD_IOC_CACHE_POLICY_COHERENT)
+                        ? cache_policy_coherent : cache_policy_noncoherent;
+
+       alternate_policy =
+               (args.alternate_policy == KFD_IOC_CACHE_POLICY_COHERENT)
+                  ? cache_policy_coherent : cache_policy_noncoherent;
+
+       if (!dev->dqm->set_cache_memory_policy(dev->dqm,
+                               &pdd->qpd,
+                               default_policy,
+                               alternate_policy,
+                               (void __user *)args.alternate_aperture_base,
+                               args.alternate_aperture_size))
+               err = -EINVAL;
+
+out:
+       mutex_unlock(&p->mutex);
+
+       return err;
+}
+
+static long kfd_ioctl_get_clock_counters(struct file *filep,
+                               struct kfd_process *p, void __user *arg)
+{
+       struct kfd_ioctl_get_clock_counters_args args;
+       struct kfd_dev *dev;
+       struct timespec time;
+
+       if (copy_from_user(&args, arg, sizeof(args)))
+               return -EFAULT;
+
+       dev = kfd_device_by_id(args.gpu_id);
+       if (dev == NULL)
+               return -EINVAL;
+
+       /* Reading GPU clock counter from KGD */
+       args.gpu_clock_counter = kfd2kgd->get_gpu_clock_counter(dev->kgd);
+
+       /* No access to rdtsc. Using raw monotonic time */
+       getrawmonotonic(&time);
+       args.cpu_clock_counter = (uint64_t)timespec_to_ns(&time);
+
+       get_monotonic_boottime(&time);
+       args.system_clock_counter = (uint64_t)timespec_to_ns(&time);
+
+       /* Since the counter is in nano-seconds we use 1GHz frequency */
+       args.system_clock_freq = 1000000000;
+
+       if (copy_to_user(arg, &args, sizeof(args)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int kfd_ioctl_get_process_apertures(struct file *filp,
+                               struct kfd_process *p, void __user *arg)
+{
+       struct kfd_ioctl_get_process_apertures_args args;
+       struct kfd_process_device_apertures *pAperture;
+       struct kfd_process_device *pdd;
+
+       dev_dbg(kfd_device, "get apertures for PASID %d", p->pasid);
+
+       if (copy_from_user(&args, arg, sizeof(args)))
+               return -EFAULT;
+
+       args.num_of_nodes = 0;
+
+       mutex_lock(&p->mutex);
+
+       /*if the process-device list isn't empty*/
+       if (kfd_has_process_device_data(p)) {
+               /* Run over all pdd of the process */
+               pdd = kfd_get_first_process_device_data(p);
+               do {
+                       pAperture = &args.process_apertures[args.num_of_nodes];
+                       pAperture->gpu_id = pdd->dev->id;
+                       pAperture->lds_base = pdd->lds_base;
+                       pAperture->lds_limit = pdd->lds_limit;
+                       pAperture->gpuvm_base = pdd->gpuvm_base;
+                       pAperture->gpuvm_limit = pdd->gpuvm_limit;
+                       pAperture->scratch_base = pdd->scratch_base;
+                       pAperture->scratch_limit = pdd->scratch_limit;
+
+                       dev_dbg(kfd_device,
+                               "node id %u\n", args.num_of_nodes);
+                       dev_dbg(kfd_device,
+                               "gpu id %u\n", pdd->dev->id);
+                       dev_dbg(kfd_device,
+                               "lds_base %llX\n", pdd->lds_base);
+                       dev_dbg(kfd_device,
+                               "lds_limit %llX\n", pdd->lds_limit);
+                       dev_dbg(kfd_device,
+                               "gpuvm_base %llX\n", pdd->gpuvm_base);
+                       dev_dbg(kfd_device,
+                               "gpuvm_limit %llX\n", pdd->gpuvm_limit);
+                       dev_dbg(kfd_device,
+                               "scratch_base %llX\n", pdd->scratch_base);
+                       dev_dbg(kfd_device,
+                               "scratch_limit %llX\n", pdd->scratch_limit);
+
+                       args.num_of_nodes++;
+               } while ((pdd = kfd_get_next_process_device_data(p, pdd)) != NULL &&
+                               (args.num_of_nodes < NUM_OF_SUPPORTED_GPUS));
+       }
+
+       mutex_unlock(&p->mutex);
+
+       if (copy_to_user(arg, &args, sizeof(args)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static long kfd_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+       struct kfd_process *process;
+       long err = -EINVAL;
+
+       dev_dbg(kfd_device,
+               "ioctl cmd 0x%x (#%d), arg 0x%lx\n",
+               cmd, _IOC_NR(cmd), arg);
+
+       process = kfd_get_process(current);
+       if (IS_ERR(process))
+               return PTR_ERR(process);
+
+       switch (cmd) {
+       case KFD_IOC_GET_VERSION:
+               err = kfd_ioctl_get_version(filep, process, (void __user *)arg);
+               break;
+       case KFD_IOC_CREATE_QUEUE:
+               err = kfd_ioctl_create_queue(filep, process,
+                                               (void __user *)arg);
+               break;
+
+       case KFD_IOC_DESTROY_QUEUE:
+               err = kfd_ioctl_destroy_queue(filep, process,
+                                               (void __user *)arg);
+               break;
+
+       case KFD_IOC_SET_MEMORY_POLICY:
+               err = kfd_ioctl_set_memory_policy(filep, process,
+                                               (void __user *)arg);
+               break;
+
+       case KFD_IOC_GET_CLOCK_COUNTERS:
+               err = kfd_ioctl_get_clock_counters(filep, process,
+                                               (void __user *)arg);
+               break;
+
+       case KFD_IOC_GET_PROCESS_APERTURES:
+               err = kfd_ioctl_get_process_apertures(filep, process,
+                                               (void __user *)arg);
+               break;
+
+       case KFD_IOC_UPDATE_QUEUE:
+               err = kfd_ioctl_update_queue(filep, process,
+                                               (void __user *)arg);
+               break;
+
+       default:
+               dev_err(kfd_device,
+                       "unknown ioctl cmd 0x%x, arg 0x%lx)\n",
+                       cmd, arg);
+               err = -EINVAL;
+               break;
+       }
+
+       if (err < 0)
+               dev_err(kfd_device,
+                       "ioctl error %ld for ioctl cmd 0x%x (#%d)\n",
+                       err, cmd, _IOC_NR(cmd));
+
+       return err;
+}
+
+static int kfd_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct kfd_process *process;
+
+       process = kfd_get_process(current);
+       if (IS_ERR(process))
+               return PTR_ERR(process);
+
+       return kfd_doorbell_mmap(process, vma);
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.h b/drivers/gpu/drm/amd/amdkfd/kfd_crat.h
new file mode 100644 (file)
index 0000000..a374fa3
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef KFD_CRAT_H_INCLUDED
+#define KFD_CRAT_H_INCLUDED
+
+#include <linux/types.h>
+
+#pragma pack(1)
+
+/*
+ * 4CC signature values for the CRAT and CDIT ACPI tables
+ */
+
+#define CRAT_SIGNATURE "CRAT"
+#define CDIT_SIGNATURE "CDIT"
+
+/*
+ * Component Resource Association Table (CRAT)
+ */
+
+#define CRAT_OEMID_LENGTH      6
+#define CRAT_OEMTABLEID_LENGTH 8
+#define CRAT_RESERVED_LENGTH   6
+
+#define CRAT_OEMID_64BIT_MASK ((1ULL << (CRAT_OEMID_LENGTH * 8)) - 1)
+
+struct crat_header {
+       uint32_t        signature;
+       uint32_t        length;
+       uint8_t         revision;
+       uint8_t         checksum;
+       uint8_t         oem_id[CRAT_OEMID_LENGTH];
+       uint8_t         oem_table_id[CRAT_OEMTABLEID_LENGTH];
+       uint32_t        oem_revision;
+       uint32_t        creator_id;
+       uint32_t        creator_revision;
+       uint32_t        total_entries;
+       uint16_t        num_domains;
+       uint8_t         reserved[CRAT_RESERVED_LENGTH];
+};
+
+/*
+ * The header structure is immediately followed by total_entries of the
+ * data definitions
+ */
+
+/*
+ * The currently defined subtype entries in the CRAT
+ */
+#define CRAT_SUBTYPE_COMPUTEUNIT_AFFINITY      0
+#define CRAT_SUBTYPE_MEMORY_AFFINITY           1
+#define CRAT_SUBTYPE_CACHE_AFFINITY            2
+#define CRAT_SUBTYPE_TLB_AFFINITY              3
+#define CRAT_SUBTYPE_CCOMPUTE_AFFINITY         4
+#define CRAT_SUBTYPE_IOLINK_AFFINITY           5
+#define CRAT_SUBTYPE_MAX                       6
+
+#define CRAT_SIBLINGMAP_SIZE   32
+
+/*
+ * ComputeUnit Affinity structure and definitions
+ */
+#define CRAT_CU_FLAGS_ENABLED          0x00000001
+#define CRAT_CU_FLAGS_HOT_PLUGGABLE    0x00000002
+#define CRAT_CU_FLAGS_CPU_PRESENT      0x00000004
+#define CRAT_CU_FLAGS_GPU_PRESENT      0x00000008
+#define CRAT_CU_FLAGS_IOMMU_PRESENT    0x00000010
+#define CRAT_CU_FLAGS_RESERVED         0xffffffe0
+
+#define CRAT_COMPUTEUNIT_RESERVED_LENGTH 4
+
+struct crat_subtype_computeunit {
+       uint8_t         type;
+       uint8_t         length;
+       uint16_t        reserved;
+       uint32_t        flags;
+       uint32_t        proximity_domain;
+       uint32_t        processor_id_low;
+       uint16_t        num_cpu_cores;
+       uint16_t        num_simd_cores;
+       uint16_t        max_waves_simd;
+       uint16_t        io_count;
+       uint16_t        hsa_capability;
+       uint16_t        lds_size_in_kb;
+       uint8_t         wave_front_size;
+       uint8_t         num_banks;
+       uint16_t        micro_engine_id;
+       uint8_t         num_arrays;
+       uint8_t         num_cu_per_array;
+       uint8_t         num_simd_per_cu;
+       uint8_t         max_slots_scatch_cu;
+       uint8_t         reserved2[CRAT_COMPUTEUNIT_RESERVED_LENGTH];
+};
+
+/*
+ * HSA Memory Affinity structure and definitions
+ */
+#define CRAT_MEM_FLAGS_ENABLED         0x00000001
+#define CRAT_MEM_FLAGS_HOT_PLUGGABLE   0x00000002
+#define CRAT_MEM_FLAGS_NON_VOLATILE    0x00000004
+#define CRAT_MEM_FLAGS_RESERVED                0xfffffff8
+
+#define CRAT_MEMORY_RESERVED_LENGTH 8
+
+struct crat_subtype_memory {
+       uint8_t         type;
+       uint8_t         length;
+       uint16_t        reserved;
+       uint32_t        flags;
+       uint32_t        promixity_domain;
+       uint32_t        base_addr_low;
+       uint32_t        base_addr_high;
+       uint32_t        length_low;
+       uint32_t        length_high;
+       uint32_t        width;
+       uint8_t         reserved2[CRAT_MEMORY_RESERVED_LENGTH];
+};
+
+/*
+ * HSA Cache Affinity structure and definitions
+ */
+#define CRAT_CACHE_FLAGS_ENABLED       0x00000001
+#define CRAT_CACHE_FLAGS_DATA_CACHE    0x00000002
+#define CRAT_CACHE_FLAGS_INST_CACHE    0x00000004
+#define CRAT_CACHE_FLAGS_CPU_CACHE     0x00000008
+#define CRAT_CACHE_FLAGS_SIMD_CACHE    0x00000010
+#define CRAT_CACHE_FLAGS_RESERVED      0xffffffe0
+
+#define CRAT_CACHE_RESERVED_LENGTH 8
+
+struct crat_subtype_cache {
+       uint8_t         type;
+       uint8_t         length;
+       uint16_t        reserved;
+       uint32_t        flags;
+       uint32_t        processor_id_low;
+       uint8_t         sibling_map[CRAT_SIBLINGMAP_SIZE];
+       uint32_t        cache_size;
+       uint8_t         cache_level;
+       uint8_t         lines_per_tag;
+       uint16_t        cache_line_size;
+       uint8_t         associativity;
+       uint8_t         cache_properties;
+       uint16_t        cache_latency;
+       uint8_t         reserved2[CRAT_CACHE_RESERVED_LENGTH];
+};
+
+/*
+ * HSA TLB Affinity structure and definitions
+ */
+#define CRAT_TLB_FLAGS_ENABLED 0x00000001
+#define CRAT_TLB_FLAGS_DATA_TLB        0x00000002
+#define CRAT_TLB_FLAGS_INST_TLB        0x00000004
+#define CRAT_TLB_FLAGS_CPU_TLB 0x00000008
+#define CRAT_TLB_FLAGS_SIMD_TLB        0x00000010
+#define CRAT_TLB_FLAGS_RESERVED        0xffffffe0
+
+#define CRAT_TLB_RESERVED_LENGTH 4
+
+struct crat_subtype_tlb {
+       uint8_t         type;
+       uint8_t         length;
+       uint16_t        reserved;
+       uint32_t        flags;
+       uint32_t        processor_id_low;
+       uint8_t         sibling_map[CRAT_SIBLINGMAP_SIZE];
+       uint32_t        tlb_level;
+       uint8_t         data_tlb_associativity_2mb;
+       uint8_t         data_tlb_size_2mb;
+       uint8_t         instruction_tlb_associativity_2mb;
+       uint8_t         instruction_tlb_size_2mb;
+       uint8_t         data_tlb_associativity_4k;
+       uint8_t         data_tlb_size_4k;
+       uint8_t         instruction_tlb_associativity_4k;
+       uint8_t         instruction_tlb_size_4k;
+       uint8_t         data_tlb_associativity_1gb;
+       uint8_t         data_tlb_size_1gb;
+       uint8_t         instruction_tlb_associativity_1gb;
+       uint8_t         instruction_tlb_size_1gb;
+       uint8_t         reserved2[CRAT_TLB_RESERVED_LENGTH];
+};
+
+/*
+ * HSA CCompute/APU Affinity structure and definitions
+ */
+#define CRAT_CCOMPUTE_FLAGS_ENABLED    0x00000001
+#define CRAT_CCOMPUTE_FLAGS_RESERVED   0xfffffffe
+
+#define CRAT_CCOMPUTE_RESERVED_LENGTH 16
+
+struct crat_subtype_ccompute {
+       uint8_t         type;
+       uint8_t         length;
+       uint16_t        reserved;
+       uint32_t        flags;
+       uint32_t        processor_id_low;
+       uint8_t         sibling_map[CRAT_SIBLINGMAP_SIZE];
+       uint32_t        apu_size;
+       uint8_t         reserved2[CRAT_CCOMPUTE_RESERVED_LENGTH];
+};
+
+/*
+ * HSA IO Link Affinity structure and definitions
+ */
+#define CRAT_IOLINK_FLAGS_ENABLED      0x00000001
+#define CRAT_IOLINK_FLAGS_COHERENCY    0x00000002
+#define CRAT_IOLINK_FLAGS_RESERVED     0xfffffffc
+
+/*
+ * IO interface types
+ */
+#define CRAT_IOLINK_TYPE_UNDEFINED     0
+#define CRAT_IOLINK_TYPE_HYPERTRANSPORT        1
+#define CRAT_IOLINK_TYPE_PCIEXPRESS    2
+#define CRAT_IOLINK_TYPE_OTHER         3
+#define CRAT_IOLINK_TYPE_MAX           255
+
+#define CRAT_IOLINK_RESERVED_LENGTH 24
+
+struct crat_subtype_iolink {
+       uint8_t         type;
+       uint8_t         length;
+       uint16_t        reserved;
+       uint32_t        flags;
+       uint32_t        proximity_domain_from;
+       uint32_t        proximity_domain_to;
+       uint8_t         io_interface_type;
+       uint8_t         version_major;
+       uint16_t        version_minor;
+       uint32_t        minimum_latency;
+       uint32_t        maximum_latency;
+       uint32_t        minimum_bandwidth_mbs;
+       uint32_t        maximum_bandwidth_mbs;
+       uint32_t        recommended_transfer_size;
+       uint8_t         reserved2[CRAT_IOLINK_RESERVED_LENGTH];
+};
+
+/*
+ * HSA generic sub-type header
+ */
+
+#define CRAT_SUBTYPE_FLAGS_ENABLED 0x00000001
+
+struct crat_subtype_generic {
+       uint8_t         type;
+       uint8_t         length;
+       uint16_t        reserved;
+       uint32_t        flags;
+};
+
+/*
+ * Component Locality Distance Information Table (CDIT)
+ */
+#define CDIT_OEMID_LENGTH      6
+#define CDIT_OEMTABLEID_LENGTH 8
+
+struct cdit_header {
+       uint32_t        signature;
+       uint32_t        length;
+       uint8_t         revision;
+       uint8_t         checksum;
+       uint8_t         oem_id[CDIT_OEMID_LENGTH];
+       uint8_t         oem_table_id[CDIT_OEMTABLEID_LENGTH];
+       uint32_t        oem_revision;
+       uint32_t        creator_id;
+       uint32_t        creator_revision;
+       uint32_t        total_entries;
+       uint16_t        num_domains;
+       uint8_t         entry[1];
+};
+
+#pragma pack()
+
+#endif /* KFD_CRAT_H_INCLUDED */
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
new file mode 100644 (file)
index 0000000..43884eb
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/amd-iommu.h>
+#include <linux/bsearch.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include "kfd_priv.h"
+#include "kfd_device_queue_manager.h"
+
+#define MQD_SIZE_ALIGNED 768
+
+static const struct kfd_device_info kaveri_device_info = {
+       .max_pasid_bits = 16,
+       .ih_ring_entry_size = 4 * sizeof(uint32_t),
+       .mqd_size_aligned = MQD_SIZE_ALIGNED
+};
+
+struct kfd_deviceid {
+       unsigned short did;
+       const struct kfd_device_info *device_info;
+};
+
+/* Please keep this sorted by increasing device id. */
+static const struct kfd_deviceid supported_devices[] = {
+       { 0x1304, &kaveri_device_info },        /* Kaveri */
+       { 0x1305, &kaveri_device_info },        /* Kaveri */
+       { 0x1306, &kaveri_device_info },        /* Kaveri */
+       { 0x1307, &kaveri_device_info },        /* Kaveri */
+       { 0x1309, &kaveri_device_info },        /* Kaveri */
+       { 0x130A, &kaveri_device_info },        /* Kaveri */
+       { 0x130B, &kaveri_device_info },        /* Kaveri */
+       { 0x130C, &kaveri_device_info },        /* Kaveri */
+       { 0x130D, &kaveri_device_info },        /* Kaveri */
+       { 0x130E, &kaveri_device_info },        /* Kaveri */
+       { 0x130F, &kaveri_device_info },        /* Kaveri */
+       { 0x1310, &kaveri_device_info },        /* Kaveri */
+       { 0x1311, &kaveri_device_info },        /* Kaveri */
+       { 0x1312, &kaveri_device_info },        /* Kaveri */
+       { 0x1313, &kaveri_device_info },        /* Kaveri */
+       { 0x1315, &kaveri_device_info },        /* Kaveri */
+       { 0x1316, &kaveri_device_info },        /* Kaveri */
+       { 0x1317, &kaveri_device_info },        /* Kaveri */
+       { 0x1318, &kaveri_device_info },        /* Kaveri */
+       { 0x131B, &kaveri_device_info },        /* Kaveri */
+       { 0x131C, &kaveri_device_info },        /* Kaveri */
+       { 0x131D, &kaveri_device_info },        /* Kaveri */
+};
+
+static const struct kfd_device_info *lookup_device_info(unsigned short did)
+{
+       size_t i;
+
+       for (i = 0; i < ARRAY_SIZE(supported_devices); i++) {
+               if (supported_devices[i].did == did) {
+                       BUG_ON(supported_devices[i].device_info == NULL);
+                       return supported_devices[i].device_info;
+               }
+       }
+
+       return NULL;
+}
+
+struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev)
+{
+       struct kfd_dev *kfd;
+
+       const struct kfd_device_info *device_info =
+                                       lookup_device_info(pdev->device);
+
+       if (!device_info)
+               return NULL;
+
+       kfd = kzalloc(sizeof(*kfd), GFP_KERNEL);
+       if (!kfd)
+               return NULL;
+
+       kfd->kgd = kgd;
+       kfd->device_info = device_info;
+       kfd->pdev = pdev;
+       kfd->init_complete = false;
+
+       return kfd;
+}
+
+static bool device_iommu_pasid_init(struct kfd_dev *kfd)
+{
+       const u32 required_iommu_flags = AMD_IOMMU_DEVICE_FLAG_ATS_SUP |
+                                       AMD_IOMMU_DEVICE_FLAG_PRI_SUP |
+                                       AMD_IOMMU_DEVICE_FLAG_PASID_SUP;
+
+       struct amd_iommu_device_info iommu_info;
+       unsigned int pasid_limit;
+       int err;
+
+       err = amd_iommu_device_info(kfd->pdev, &iommu_info);
+       if (err < 0) {
+               dev_err(kfd_device,
+                       "error getting iommu info. is the iommu enabled?\n");
+               return false;
+       }
+
+       if ((iommu_info.flags & required_iommu_flags) != required_iommu_flags) {
+               dev_err(kfd_device, "error required iommu flags ats(%i), pri(%i), pasid(%i)\n",
+                      (iommu_info.flags & AMD_IOMMU_DEVICE_FLAG_ATS_SUP) != 0,
+                      (iommu_info.flags & AMD_IOMMU_DEVICE_FLAG_PRI_SUP) != 0,
+                      (iommu_info.flags & AMD_IOMMU_DEVICE_FLAG_PASID_SUP) != 0);
+               return false;
+       }
+
+       pasid_limit = min_t(unsigned int,
+                       (unsigned int)1 << kfd->device_info->max_pasid_bits,
+                       iommu_info.max_pasids);
+       /*
+        * last pasid is used for kernel queues doorbells
+        * in the future the last pasid might be used for a kernel thread.
+        */
+       pasid_limit = min_t(unsigned int,
+                               pasid_limit,
+                               kfd->doorbell_process_limit - 1);
+
+       err = amd_iommu_init_device(kfd->pdev, pasid_limit);
+       if (err < 0) {
+               dev_err(kfd_device, "error initializing iommu device\n");
+               return false;
+       }
+
+       if (!kfd_set_pasid_limit(pasid_limit)) {
+               dev_err(kfd_device, "error setting pasid limit\n");
+               amd_iommu_free_device(kfd->pdev);
+               return false;
+       }
+
+       return true;
+}
+
+static void iommu_pasid_shutdown_callback(struct pci_dev *pdev, int pasid)
+{
+       struct kfd_dev *dev = kfd_device_by_pci_dev(pdev);
+
+       if (dev)
+               kfd_unbind_process_from_device(dev, pasid);
+}
+
+bool kgd2kfd_device_init(struct kfd_dev *kfd,
+                        const struct kgd2kfd_shared_resources *gpu_resources)
+{
+       unsigned int size;
+
+       kfd->shared_resources = *gpu_resources;
+
+       /* calculate max size of mqds needed for queues */
+       size = max_num_of_processes *
+               max_num_of_queues_per_process *
+               kfd->device_info->mqd_size_aligned;
+
+       /* add another 512KB for all other allocations on gart */
+       size += 512 * 1024;
+
+       if (kfd2kgd->init_sa_manager(kfd->kgd, size)) {
+               dev_err(kfd_device,
+                       "Error initializing sa manager for device (%x:%x)\n",
+                       kfd->pdev->vendor, kfd->pdev->device);
+               goto out;
+       }
+
+       kfd_doorbell_init(kfd);
+
+       if (kfd_topology_add_device(kfd) != 0) {
+               dev_err(kfd_device,
+                       "Error adding device (%x:%x) to topology\n",
+                       kfd->pdev->vendor, kfd->pdev->device);
+               goto kfd_topology_add_device_error;
+       }
+
+       if (kfd_interrupt_init(kfd)) {
+               dev_err(kfd_device,
+                       "Error initializing interrupts for device (%x:%x)\n",
+                       kfd->pdev->vendor, kfd->pdev->device);
+               goto kfd_interrupt_error;
+       }
+
+       if (!device_iommu_pasid_init(kfd)) {
+               dev_err(kfd_device,
+                       "Error initializing iommuv2 for device (%x:%x)\n",
+                       kfd->pdev->vendor, kfd->pdev->device);
+               goto device_iommu_pasid_error;
+       }
+       amd_iommu_set_invalidate_ctx_cb(kfd->pdev,
+                                               iommu_pasid_shutdown_callback);
+
+       kfd->dqm = device_queue_manager_init(kfd);
+       if (!kfd->dqm) {
+               dev_err(kfd_device,
+                       "Error initializing queue manager for device (%x:%x)\n",
+                       kfd->pdev->vendor, kfd->pdev->device);
+               goto device_queue_manager_error;
+       }
+
+       if (kfd->dqm->start(kfd->dqm) != 0) {
+               dev_err(kfd_device,
+                       "Error starting queuen manager for device (%x:%x)\n",
+                       kfd->pdev->vendor, kfd->pdev->device);
+               goto dqm_start_error;
+       }
+
+       kfd->init_complete = true;
+       dev_info(kfd_device, "added device (%x:%x)\n", kfd->pdev->vendor,
+                kfd->pdev->device);
+
+       pr_debug("kfd: Starting kfd with the following scheduling policy %d\n",
+               sched_policy);
+
+       goto out;
+
+dqm_start_error:
+       device_queue_manager_uninit(kfd->dqm);
+device_queue_manager_error:
+       amd_iommu_free_device(kfd->pdev);
+device_iommu_pasid_error:
+       kfd_interrupt_exit(kfd);
+kfd_interrupt_error:
+       kfd_topology_remove_device(kfd);
+kfd_topology_add_device_error:
+       kfd2kgd->fini_sa_manager(kfd->kgd);
+       dev_err(kfd_device,
+               "device (%x:%x) NOT added due to errors\n",
+               kfd->pdev->vendor, kfd->pdev->device);
+out:
+       return kfd->init_complete;
+}
+
+void kgd2kfd_device_exit(struct kfd_dev *kfd)
+{
+       if (kfd->init_complete) {
+               device_queue_manager_uninit(kfd->dqm);
+               amd_iommu_free_device(kfd->pdev);
+               kfd_interrupt_exit(kfd);
+               kfd_topology_remove_device(kfd);
+       }
+
+       kfree(kfd);
+}
+
+void kgd2kfd_suspend(struct kfd_dev *kfd)
+{
+       BUG_ON(kfd == NULL);
+
+       if (kfd->init_complete) {
+               kfd->dqm->stop(kfd->dqm);
+               amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL);
+               amd_iommu_free_device(kfd->pdev);
+       }
+}
+
+int kgd2kfd_resume(struct kfd_dev *kfd)
+{
+       unsigned int pasid_limit;
+       int err;
+
+       BUG_ON(kfd == NULL);
+
+       pasid_limit = kfd_get_pasid_limit();
+
+       if (kfd->init_complete) {
+               err = amd_iommu_init_device(kfd->pdev, pasid_limit);
+               if (err < 0)
+                       return -ENXIO;
+               amd_iommu_set_invalidate_ctx_cb(kfd->pdev,
+                                               iommu_pasid_shutdown_callback);
+               kfd->dqm->start(kfd->dqm);
+       }
+
+       return 0;
+}
+
+/* This is called directly from KGD at ISR. */
+void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry)
+{
+       if (kfd->init_complete) {
+               spin_lock(&kfd->interrupt_lock);
+
+               if (kfd->interrupts_active
+                   && enqueue_ih_ring_entry(kfd, ih_ring_entry))
+                       schedule_work(&kfd->interrupt_work);
+
+               spin_unlock(&kfd->interrupt_lock);
+       }
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
new file mode 100644 (file)
index 0000000..924e90c
--- /dev/null
@@ -0,0 +1,1062 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/printk.h>
+#include <linux/bitops.h>
+#include "kfd_priv.h"
+#include "kfd_device_queue_manager.h"
+#include "kfd_mqd_manager.h"
+#include "cik_regs.h"
+#include "kfd_kernel_queue.h"
+#include "../../radeon/cik_reg.h"
+
+/* Size of the per-pipe EOP queue */
+#define CIK_HPD_EOP_BYTES_LOG2 11
+#define CIK_HPD_EOP_BYTES (1U << CIK_HPD_EOP_BYTES_LOG2)
+
+static bool is_mem_initialized;
+
+static int init_memory(struct device_queue_manager *dqm);
+static int set_pasid_vmid_mapping(struct device_queue_manager *dqm,
+                                       unsigned int pasid, unsigned int vmid);
+
+static int create_compute_queue_nocpsch(struct device_queue_manager *dqm,
+                                       struct queue *q,
+                                       struct qcm_process_device *qpd);
+static int execute_queues_cpsch(struct device_queue_manager *dqm, bool lock);
+static int destroy_queues_cpsch(struct device_queue_manager *dqm, bool lock);
+
+
+static inline unsigned int get_pipes_num(struct device_queue_manager *dqm)
+{
+       BUG_ON(!dqm || !dqm->dev);
+       return dqm->dev->shared_resources.compute_pipe_count;
+}
+
+static inline unsigned int get_first_pipe(struct device_queue_manager *dqm)
+{
+       BUG_ON(!dqm);
+       return dqm->dev->shared_resources.first_compute_pipe;
+}
+
+static inline unsigned int get_pipes_num_cpsch(void)
+{
+       return PIPE_PER_ME_CP_SCHEDULING;
+}
+
+static inline unsigned int
+get_sh_mem_bases_nybble_64(struct kfd_process_device *pdd)
+{
+       uint32_t nybble;
+
+       nybble = (pdd->lds_base >> 60) & 0x0E;
+
+       return nybble;
+
+}
+
+static inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd)
+{
+       unsigned int shared_base;
+
+       shared_base = (pdd->lds_base >> 16) & 0xFF;
+
+       return shared_base;
+}
+
+static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble);
+static void init_process_memory(struct device_queue_manager *dqm,
+                               struct qcm_process_device *qpd)
+{
+       struct kfd_process_device *pdd;
+       unsigned int temp;
+
+       BUG_ON(!dqm || !qpd);
+
+       pdd = qpd_to_pdd(qpd);
+
+       /* check if sh_mem_config register already configured */
+       if (qpd->sh_mem_config == 0) {
+               qpd->sh_mem_config =
+                       ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED) |
+                       DEFAULT_MTYPE(MTYPE_NONCACHED) |
+                       APE1_MTYPE(MTYPE_NONCACHED);
+               qpd->sh_mem_ape1_limit = 0;
+               qpd->sh_mem_ape1_base = 0;
+       }
+
+       if (qpd->pqm->process->is_32bit_user_mode) {
+               temp = get_sh_mem_bases_32(pdd);
+               qpd->sh_mem_bases = SHARED_BASE(temp);
+               qpd->sh_mem_config |= PTR32;
+       } else {
+               temp = get_sh_mem_bases_nybble_64(pdd);
+               qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp);
+       }
+
+       pr_debug("kfd: is32bit process: %d sh_mem_bases nybble: 0x%X and register 0x%X\n",
+               qpd->pqm->process->is_32bit_user_mode, temp, qpd->sh_mem_bases);
+}
+
+static void program_sh_mem_settings(struct device_queue_manager *dqm,
+                                       struct qcm_process_device *qpd)
+{
+       return kfd2kgd->program_sh_mem_settings(dqm->dev->kgd, qpd->vmid,
+                                               qpd->sh_mem_config,
+                                               qpd->sh_mem_ape1_base,
+                                               qpd->sh_mem_ape1_limit,
+                                               qpd->sh_mem_bases);
+}
+
+static int allocate_vmid(struct device_queue_manager *dqm,
+                       struct qcm_process_device *qpd,
+                       struct queue *q)
+{
+       int bit, allocated_vmid;
+
+       if (dqm->vmid_bitmap == 0)
+               return -ENOMEM;
+
+       bit = find_first_bit((unsigned long *)&dqm->vmid_bitmap, CIK_VMID_NUM);
+       clear_bit(bit, (unsigned long *)&dqm->vmid_bitmap);
+
+       /* Kaveri kfd vmid's starts from vmid 8 */
+       allocated_vmid = bit + KFD_VMID_START_OFFSET;
+       pr_debug("kfd: vmid allocation %d\n", allocated_vmid);
+       qpd->vmid = allocated_vmid;
+       q->properties.vmid = allocated_vmid;
+
+       set_pasid_vmid_mapping(dqm, q->process->pasid, q->properties.vmid);
+       program_sh_mem_settings(dqm, qpd);
+
+       return 0;
+}
+
+static void deallocate_vmid(struct device_queue_manager *dqm,
+                               struct qcm_process_device *qpd,
+                               struct queue *q)
+{
+       int bit = qpd->vmid - KFD_VMID_START_OFFSET;
+
+       set_bit(bit, (unsigned long *)&dqm->vmid_bitmap);
+       qpd->vmid = 0;
+       q->properties.vmid = 0;
+}
+
+static int create_queue_nocpsch(struct device_queue_manager *dqm,
+                               struct queue *q,
+                               struct qcm_process_device *qpd,
+                               int *allocated_vmid)
+{
+       int retval;
+
+       BUG_ON(!dqm || !q || !qpd || !allocated_vmid);
+
+       pr_debug("kfd: In func %s\n", __func__);
+       print_queue(q);
+
+       mutex_lock(&dqm->lock);
+
+       if (list_empty(&qpd->queues_list)) {
+               retval = allocate_vmid(dqm, qpd, q);
+               if (retval != 0) {
+                       mutex_unlock(&dqm->lock);
+                       return retval;
+               }
+       }
+       *allocated_vmid = qpd->vmid;
+       q->properties.vmid = qpd->vmid;
+
+       retval = create_compute_queue_nocpsch(dqm, q, qpd);
+
+       if (retval != 0) {
+               if (list_empty(&qpd->queues_list)) {
+                       deallocate_vmid(dqm, qpd, q);
+                       *allocated_vmid = 0;
+               }
+               mutex_unlock(&dqm->lock);
+               return retval;
+       }
+
+       list_add(&q->list, &qpd->queues_list);
+       dqm->queue_count++;
+
+       mutex_unlock(&dqm->lock);
+       return 0;
+}
+
+static int allocate_hqd(struct device_queue_manager *dqm, struct queue *q)
+{
+       bool set;
+       int pipe, bit;
+
+       set = false;
+
+       for (pipe = dqm->next_pipe_to_allocate; pipe < get_pipes_num(dqm);
+                       pipe = (pipe + 1) % get_pipes_num(dqm)) {
+               if (dqm->allocated_queues[pipe] != 0) {
+                       bit = find_first_bit(
+                               (unsigned long *)&dqm->allocated_queues[pipe],
+                               QUEUES_PER_PIPE);
+
+                       clear_bit(bit,
+                               (unsigned long *)&dqm->allocated_queues[pipe]);
+                       q->pipe = pipe;
+                       q->queue = bit;
+                       set = true;
+                       break;
+               }
+       }
+
+       if (set == false)
+               return -EBUSY;
+
+       pr_debug("kfd: DQM %s hqd slot - pipe (%d) queue(%d)\n",
+                               __func__, q->pipe, q->queue);
+       /* horizontal hqd allocation */
+       dqm->next_pipe_to_allocate = (pipe + 1) % get_pipes_num(dqm);
+
+       return 0;
+}
+
+static inline void deallocate_hqd(struct device_queue_manager *dqm,
+                               struct queue *q)
+{
+       set_bit(q->queue, (unsigned long *)&dqm->allocated_queues[q->pipe]);
+}
+
+static int create_compute_queue_nocpsch(struct device_queue_manager *dqm,
+                                       struct queue *q,
+                                       struct qcm_process_device *qpd)
+{
+       int retval;
+       struct mqd_manager *mqd;
+
+       BUG_ON(!dqm || !q || !qpd);
+
+       mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE);
+       if (mqd == NULL)
+               return -ENOMEM;
+
+       retval = allocate_hqd(dqm, q);
+       if (retval != 0)
+               return retval;
+
+       retval = mqd->init_mqd(mqd, &q->mqd, &q->mqd_mem_obj,
+                               &q->gart_mqd_addr, &q->properties);
+       if (retval != 0) {
+               deallocate_hqd(dqm, q);
+               return retval;
+       }
+
+       return 0;
+}
+
+static int destroy_queue_nocpsch(struct device_queue_manager *dqm,
+                               struct qcm_process_device *qpd,
+                               struct queue *q)
+{
+       int retval;
+       struct mqd_manager *mqd;
+
+       BUG_ON(!dqm || !q || !q->mqd || !qpd);
+
+       retval = 0;
+
+       pr_debug("kfd: In Func %s\n", __func__);
+
+       mutex_lock(&dqm->lock);
+       mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE);
+       if (mqd == NULL) {
+               retval = -ENOMEM;
+               goto out;
+       }
+
+       retval = mqd->destroy_mqd(mqd, q->mqd,
+                               KFD_PREEMPT_TYPE_WAVEFRONT,
+                               QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS,
+                               q->pipe, q->queue);
+
+       if (retval != 0)
+               goto out;
+
+       deallocate_hqd(dqm, q);
+
+       mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj);
+
+       list_del(&q->list);
+       if (list_empty(&qpd->queues_list))
+               deallocate_vmid(dqm, qpd, q);
+       dqm->queue_count--;
+out:
+       mutex_unlock(&dqm->lock);
+       return retval;
+}
+
+static int update_queue(struct device_queue_manager *dqm, struct queue *q)
+{
+       int retval;
+       struct mqd_manager *mqd;
+
+       BUG_ON(!dqm || !q || !q->mqd);
+
+       mutex_lock(&dqm->lock);
+       mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE);
+       if (mqd == NULL) {
+               mutex_unlock(&dqm->lock);
+               return -ENOMEM;
+       }
+
+       retval = mqd->update_mqd(mqd, q->mqd, &q->properties);
+       if (q->properties.is_active == true)
+               dqm->queue_count++;
+       else
+               dqm->queue_count--;
+
+       if (sched_policy != KFD_SCHED_POLICY_NO_HWS)
+               retval = execute_queues_cpsch(dqm, false);
+
+       mutex_unlock(&dqm->lock);
+       return retval;
+}
+
+static struct mqd_manager *get_mqd_manager_nocpsch(
+               struct device_queue_manager *dqm, enum KFD_MQD_TYPE type)
+{
+       struct mqd_manager *mqd;
+
+       BUG_ON(!dqm || type >= KFD_MQD_TYPE_MAX);
+
+       pr_debug("kfd: In func %s mqd type %d\n", __func__, type);
+
+       mqd = dqm->mqds[type];
+       if (!mqd) {
+               mqd = mqd_manager_init(type, dqm->dev);
+               if (mqd == NULL)
+                       pr_err("kfd: mqd manager is NULL");
+               dqm->mqds[type] = mqd;
+       }
+
+       return mqd;
+}
+
+static int register_process_nocpsch(struct device_queue_manager *dqm,
+                                       struct qcm_process_device *qpd)
+{
+       struct device_process_node *n;
+
+       BUG_ON(!dqm || !qpd);
+
+       pr_debug("kfd: In func %s\n", __func__);
+
+       n = kzalloc(sizeof(struct device_process_node), GFP_KERNEL);
+       if (!n)
+               return -ENOMEM;
+
+       n->qpd = qpd;
+
+       mutex_lock(&dqm->lock);
+       list_add(&n->list, &dqm->queues);
+
+       init_process_memory(dqm, qpd);
+       dqm->processes_count++;
+
+       mutex_unlock(&dqm->lock);
+
+       return 0;
+}
+
+static int unregister_process_nocpsch(struct device_queue_manager *dqm,
+                                       struct qcm_process_device *qpd)
+{
+       int retval;
+       struct device_process_node *cur, *next;
+
+       BUG_ON(!dqm || !qpd);
+
+       BUG_ON(!list_empty(&qpd->queues_list));
+
+       pr_debug("kfd: In func %s\n", __func__);
+
+       retval = 0;
+       mutex_lock(&dqm->lock);
+
+       list_for_each_entry_safe(cur, next, &dqm->queues, list) {
+               if (qpd == cur->qpd) {
+                       list_del(&cur->list);
+                       kfree(cur);
+                       dqm->processes_count--;
+                       goto out;
+               }
+       }
+       /* qpd not found in dqm list */
+       retval = 1;
+out:
+       mutex_unlock(&dqm->lock);
+       return retval;
+}
+
+static int
+set_pasid_vmid_mapping(struct device_queue_manager *dqm, unsigned int pasid,
+                       unsigned int vmid)
+{
+       uint32_t pasid_mapping;
+
+       pasid_mapping = (pasid == 0) ? 0 : (uint32_t)pasid |
+                                               ATC_VMID_PASID_MAPPING_VALID;
+       return kfd2kgd->set_pasid_vmid_mapping(dqm->dev->kgd, pasid_mapping,
+                                               vmid);
+}
+
+static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble)
+{
+       /* In 64-bit mode, we can only control the top 3 bits of the LDS,
+        * scratch and GPUVM apertures.
+        * The hardware fills in the remaining 59 bits according to the
+        * following pattern:
+        * LDS:         X0000000'00000000 - X0000001'00000000 (4GB)
+        * Scratch:     X0000001'00000000 - X0000002'00000000 (4GB)
+        * GPUVM:       Y0010000'00000000 - Y0020000'00000000 (1TB)
+        *
+        * (where X/Y is the configurable nybble with the low-bit 0)
+        *
+        * LDS and scratch will have the same top nybble programmed in the
+        * top 3 bits of SH_MEM_BASES.PRIVATE_BASE.
+        * GPUVM can have a different top nybble programmed in the
+        * top 3 bits of SH_MEM_BASES.SHARED_BASE.
+        * We don't bother to support different top nybbles
+        * for LDS/Scratch and GPUVM.
+        */
+
+       BUG_ON((top_address_nybble & 1) || top_address_nybble > 0xE ||
+               top_address_nybble == 0);
+
+       return PRIVATE_BASE(top_address_nybble << 12) |
+                       SHARED_BASE(top_address_nybble << 12);
+}
+
+static int init_memory(struct device_queue_manager *dqm)
+{
+       int i, retval;
+
+       for (i = 8; i < 16; i++)
+               set_pasid_vmid_mapping(dqm, 0, i);
+
+       retval = kfd2kgd->init_memory(dqm->dev->kgd);
+       if (retval == 0)
+               is_mem_initialized = true;
+       return retval;
+}
+
+
+static int init_pipelines(struct device_queue_manager *dqm,
+                       unsigned int pipes_num, unsigned int first_pipe)
+{
+       void *hpdptr;
+       struct mqd_manager *mqd;
+       unsigned int i, err, inx;
+       uint64_t pipe_hpd_addr;
+
+       BUG_ON(!dqm || !dqm->dev);
+
+       pr_debug("kfd: In func %s\n", __func__);
+
+       /*
+        * Allocate memory for the HPDs. This is hardware-owned per-pipe data.
+        * The driver never accesses this memory after zeroing it.
+        * It doesn't even have to be saved/restored on suspend/resume
+        * because it contains no data when there are no active queues.
+        */
+
+       err = kfd2kgd->allocate_mem(dqm->dev->kgd,
+                               CIK_HPD_EOP_BYTES * pipes_num,
+                               PAGE_SIZE,
+                               KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
+                               (struct kgd_mem **) &dqm->pipeline_mem);
+
+       if (err) {
+               pr_err("kfd: error allocate vidmem num pipes: %d\n",
+                       pipes_num);
+               return -ENOMEM;
+       }
+
+       hpdptr = dqm->pipeline_mem->cpu_ptr;
+       dqm->pipelines_addr = dqm->pipeline_mem->gpu_addr;
+
+       memset(hpdptr, 0, CIK_HPD_EOP_BYTES * pipes_num);
+
+       mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE);
+       if (mqd == NULL) {
+               kfd2kgd->free_mem(dqm->dev->kgd,
+                               (struct kgd_mem *) dqm->pipeline_mem);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < pipes_num; i++) {
+               inx = i + first_pipe;
+               pipe_hpd_addr = dqm->pipelines_addr + i * CIK_HPD_EOP_BYTES;
+               pr_debug("kfd: pipeline address %llX\n", pipe_hpd_addr);
+               /* = log2(bytes/4)-1 */
+               kfd2kgd->init_pipeline(dqm->dev->kgd, i,
+                               CIK_HPD_EOP_BYTES_LOG2 - 3, pipe_hpd_addr);
+       }
+
+       return 0;
+}
+
+
+static int init_scheduler(struct device_queue_manager *dqm)
+{
+       int retval;
+
+       BUG_ON(!dqm);
+
+       pr_debug("kfd: In %s\n", __func__);
+
+       retval = init_pipelines(dqm, get_pipes_num(dqm), KFD_DQM_FIRST_PIPE);
+       if (retval != 0)
+               return retval;
+
+       retval = init_memory(dqm);
+
+       return retval;
+}
+
+static int initialize_nocpsch(struct device_queue_manager *dqm)
+{
+       int i;
+
+       BUG_ON(!dqm);
+
+       pr_debug("kfd: In func %s num of pipes: %d\n",
+                       __func__, get_pipes_num(dqm));
+
+       mutex_init(&dqm->lock);
+       INIT_LIST_HEAD(&dqm->queues);
+       dqm->queue_count = dqm->next_pipe_to_allocate = 0;
+       dqm->allocated_queues = kcalloc(get_pipes_num(dqm),
+                                       sizeof(unsigned int), GFP_KERNEL);
+       if (!dqm->allocated_queues) {
+               mutex_destroy(&dqm->lock);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < get_pipes_num(dqm); i++)
+               dqm->allocated_queues[i] = (1 << QUEUES_PER_PIPE) - 1;
+
+       dqm->vmid_bitmap = (1 << VMID_PER_DEVICE) - 1;
+
+       init_scheduler(dqm);
+       return 0;
+}
+
+static void uninitialize_nocpsch(struct device_queue_manager *dqm)
+{
+       int i;
+
+       BUG_ON(!dqm);
+
+       BUG_ON(dqm->queue_count > 0 || dqm->processes_count > 0);
+
+       kfree(dqm->allocated_queues);
+       for (i = 0 ; i < KFD_MQD_TYPE_MAX ; i++)
+               kfree(dqm->mqds[i]);
+       mutex_destroy(&dqm->lock);
+       kfd2kgd->free_mem(dqm->dev->kgd,
+                       (struct kgd_mem *) dqm->pipeline_mem);
+}
+
+static int start_nocpsch(struct device_queue_manager *dqm)
+{
+       return 0;
+}
+
+static int stop_nocpsch(struct device_queue_manager *dqm)
+{
+       return 0;
+}
+
+/*
+ * Device Queue Manager implementation for cp scheduler
+ */
+
+static int set_sched_resources(struct device_queue_manager *dqm)
+{
+       struct scheduling_resources res;
+       unsigned int queue_num, queue_mask;
+
+       BUG_ON(!dqm);
+
+       pr_debug("kfd: In func %s\n", __func__);
+
+       queue_num = get_pipes_num_cpsch() * QUEUES_PER_PIPE;
+       queue_mask = (1 << queue_num) - 1;
+       res.vmid_mask = (1 << VMID_PER_DEVICE) - 1;
+       res.vmid_mask <<= KFD_VMID_START_OFFSET;
+       res.queue_mask = queue_mask << (get_first_pipe(dqm) * QUEUES_PER_PIPE);
+       res.gws_mask = res.oac_mask = res.gds_heap_base =
+                                               res.gds_heap_size = 0;
+
+       pr_debug("kfd: scheduling resources:\n"
+                       "      vmid mask: 0x%8X\n"
+                       "      queue mask: 0x%8llX\n",
+                       res.vmid_mask, res.queue_mask);
+
+       return pm_send_set_resources(&dqm->packets, &res);
+}
+
+static int initialize_cpsch(struct device_queue_manager *dqm)
+{
+       int retval;
+
+       BUG_ON(!dqm);
+
+       pr_debug("kfd: In func %s num of pipes: %d\n",
+                       __func__, get_pipes_num_cpsch());
+
+       mutex_init(&dqm->lock);
+       INIT_LIST_HEAD(&dqm->queues);
+       dqm->queue_count = dqm->processes_count = 0;
+       dqm->active_runlist = false;
+       retval = init_pipelines(dqm, get_pipes_num(dqm), 0);
+       if (retval != 0)
+               goto fail_init_pipelines;
+
+       return 0;
+
+fail_init_pipelines:
+       mutex_destroy(&dqm->lock);
+       return retval;
+}
+
+static int start_cpsch(struct device_queue_manager *dqm)
+{
+       struct device_process_node *node;
+       int retval;
+
+       BUG_ON(!dqm);
+
+       retval = 0;
+
+       retval = pm_init(&dqm->packets, dqm);
+       if (retval != 0)
+               goto fail_packet_manager_init;
+
+       retval = set_sched_resources(dqm);
+       if (retval != 0)
+               goto fail_set_sched_resources;
+
+       pr_debug("kfd: allocating fence memory\n");
+
+       /* allocate fence memory on the gart */
+       retval = kfd2kgd->allocate_mem(dqm->dev->kgd,
+                                       sizeof(*dqm->fence_addr),
+                                       32,
+                                       KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
+                                       (struct kgd_mem **) &dqm->fence_mem);
+
+       if (retval != 0)
+               goto fail_allocate_vidmem;
+
+       dqm->fence_addr = dqm->fence_mem->cpu_ptr;
+       dqm->fence_gpu_addr = dqm->fence_mem->gpu_addr;
+
+       list_for_each_entry(node, &dqm->queues, list)
+               if (node->qpd->pqm->process && dqm->dev)
+                       kfd_bind_process_to_device(dqm->dev,
+                                               node->qpd->pqm->process);
+
+       execute_queues_cpsch(dqm, true);
+
+       return 0;
+fail_allocate_vidmem:
+fail_set_sched_resources:
+       pm_uninit(&dqm->packets);
+fail_packet_manager_init:
+       return retval;
+}
+
+static int stop_cpsch(struct device_queue_manager *dqm)
+{
+       struct device_process_node *node;
+       struct kfd_process_device *pdd;
+
+       BUG_ON(!dqm);
+
+       destroy_queues_cpsch(dqm, true);
+
+       list_for_each_entry(node, &dqm->queues, list) {
+               pdd = qpd_to_pdd(node->qpd);
+               pdd->bound = false;
+       }
+       kfd2kgd->free_mem(dqm->dev->kgd,
+                       (struct kgd_mem *) dqm->fence_mem);
+       pm_uninit(&dqm->packets);
+
+       return 0;
+}
+
+static int create_kernel_queue_cpsch(struct device_queue_manager *dqm,
+                                       struct kernel_queue *kq,
+                                       struct qcm_process_device *qpd)
+{
+       BUG_ON(!dqm || !kq || !qpd);
+
+       pr_debug("kfd: In func %s\n", __func__);
+
+       mutex_lock(&dqm->lock);
+       list_add(&kq->list, &qpd->priv_queue_list);
+       dqm->queue_count++;
+       qpd->is_debug = true;
+       execute_queues_cpsch(dqm, false);
+       mutex_unlock(&dqm->lock);
+
+       return 0;
+}
+
+static void destroy_kernel_queue_cpsch(struct device_queue_manager *dqm,
+                                       struct kernel_queue *kq,
+                                       struct qcm_process_device *qpd)
+{
+       BUG_ON(!dqm || !kq);
+
+       pr_debug("kfd: In %s\n", __func__);
+
+       mutex_lock(&dqm->lock);
+       destroy_queues_cpsch(dqm, false);
+       list_del(&kq->list);
+       dqm->queue_count--;
+       qpd->is_debug = false;
+       execute_queues_cpsch(dqm, false);
+       mutex_unlock(&dqm->lock);
+}
+
+static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
+                       struct qcm_process_device *qpd, int *allocate_vmid)
+{
+       int retval;
+       struct mqd_manager *mqd;
+
+       BUG_ON(!dqm || !q || !qpd);
+
+       retval = 0;
+
+       if (allocate_vmid)
+               *allocate_vmid = 0;
+
+       mutex_lock(&dqm->lock);
+
+       mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_CP);
+       if (mqd == NULL) {
+               mutex_unlock(&dqm->lock);
+               return -ENOMEM;
+       }
+
+       retval = mqd->init_mqd(mqd, &q->mqd, &q->mqd_mem_obj,
+                               &q->gart_mqd_addr, &q->properties);
+       if (retval != 0)
+               goto out;
+
+       list_add(&q->list, &qpd->queues_list);
+       if (q->properties.is_active) {
+               dqm->queue_count++;
+               retval = execute_queues_cpsch(dqm, false);
+       }
+
+out:
+       mutex_unlock(&dqm->lock);
+       return retval;
+}
+
+static int fence_wait_timeout(unsigned int *fence_addr,
+                               unsigned int fence_value,
+                               unsigned long timeout)
+{
+       BUG_ON(!fence_addr);
+       timeout += jiffies;
+
+       while (*fence_addr != fence_value) {
+               if (time_after(jiffies, timeout)) {
+                       pr_err("kfd: qcm fence wait loop timeout expired\n");
+                       return -ETIME;
+               }
+               cpu_relax();
+       }
+
+       return 0;
+}
+
+static int destroy_queues_cpsch(struct device_queue_manager *dqm, bool lock)
+{
+       int retval;
+
+       BUG_ON(!dqm);
+
+       retval = 0;
+
+       if (lock)
+               mutex_lock(&dqm->lock);
+       if (dqm->active_runlist == false)
+               goto out;
+       retval = pm_send_unmap_queue(&dqm->packets, KFD_QUEUE_TYPE_COMPUTE,
+                       KFD_PREEMPT_TYPE_FILTER_ALL_QUEUES, 0, false, 0);
+       if (retval != 0)
+               goto out;
+
+       *dqm->fence_addr = KFD_FENCE_INIT;
+       pm_send_query_status(&dqm->packets, dqm->fence_gpu_addr,
+                               KFD_FENCE_COMPLETED);
+       /* should be timed out */
+       fence_wait_timeout(dqm->fence_addr, KFD_FENCE_COMPLETED,
+                               QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS);
+       pm_release_ib(&dqm->packets);
+       dqm->active_runlist = false;
+
+out:
+       if (lock)
+               mutex_unlock(&dqm->lock);
+       return retval;
+}
+
+static int execute_queues_cpsch(struct device_queue_manager *dqm, bool lock)
+{
+       int retval;
+
+       BUG_ON(!dqm);
+
+       if (lock)
+               mutex_lock(&dqm->lock);
+
+       retval = destroy_queues_cpsch(dqm, false);
+       if (retval != 0) {
+               pr_err("kfd: the cp might be in an unrecoverable state due to an unsuccessful queues preemption");
+               goto out;
+       }
+
+       if (dqm->queue_count <= 0 || dqm->processes_count <= 0) {
+               retval = 0;
+               goto out;
+       }
+
+       if (dqm->active_runlist) {
+               retval = 0;
+               goto out;
+       }
+
+       retval = pm_send_runlist(&dqm->packets, &dqm->queues);
+       if (retval != 0) {
+               pr_err("kfd: failed to execute runlist");
+               goto out;
+       }
+       dqm->active_runlist = true;
+
+out:
+       if (lock)
+               mutex_unlock(&dqm->lock);
+       return retval;
+}
+
+static int destroy_queue_cpsch(struct device_queue_manager *dqm,
+                               struct qcm_process_device *qpd,
+                               struct queue *q)
+{
+       int retval;
+       struct mqd_manager *mqd;
+
+       BUG_ON(!dqm || !qpd || !q);
+
+       retval = 0;
+
+       /* remove queue from list to prevent rescheduling after preemption */
+       mutex_lock(&dqm->lock);
+
+       mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_CP);
+       if (!mqd) {
+               retval = -ENOMEM;
+               goto failed;
+       }
+
+       list_del(&q->list);
+       dqm->queue_count--;
+
+       execute_queues_cpsch(dqm, false);
+
+       mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj);
+
+       mutex_unlock(&dqm->lock);
+
+       return 0;
+
+failed:
+       mutex_unlock(&dqm->lock);
+       return retval;
+}
+
+/*
+ * Low bits must be 0000/FFFF as required by HW, high bits must be 0 to
+ * stay in user mode.
+ */
+#define APE1_FIXED_BITS_MASK 0xFFFF80000000FFFFULL
+/* APE1 limit is inclusive and 64K aligned. */
+#define APE1_LIMIT_ALIGNMENT 0xFFFF
+
+static bool set_cache_memory_policy(struct device_queue_manager *dqm,
+                                  struct qcm_process_device *qpd,
+                                  enum cache_policy default_policy,
+                                  enum cache_policy alternate_policy,
+                                  void __user *alternate_aperture_base,
+                                  uint64_t alternate_aperture_size)
+{
+       uint32_t default_mtype;
+       uint32_t ape1_mtype;
+
+       pr_debug("kfd: In func %s\n", __func__);
+
+       mutex_lock(&dqm->lock);
+
+       if (alternate_aperture_size == 0) {
+               /* base > limit disables APE1 */
+               qpd->sh_mem_ape1_base = 1;
+               qpd->sh_mem_ape1_limit = 0;
+       } else {
+               /*
+                * In FSA64, APE1_Base[63:0] = { 16{SH_MEM_APE1_BASE[31]},
+                *                      SH_MEM_APE1_BASE[31:0], 0x0000 }
+                * APE1_Limit[63:0] = { 16{SH_MEM_APE1_LIMIT[31]},
+                *                      SH_MEM_APE1_LIMIT[31:0], 0xFFFF }
+                * Verify that the base and size parameters can be
+                * represented in this format and convert them.
+                * Additionally restrict APE1 to user-mode addresses.
+                */
+
+               uint64_t base = (uintptr_t)alternate_aperture_base;
+               uint64_t limit = base + alternate_aperture_size - 1;
+
+               if (limit <= base)
+                       goto out;
+
+               if ((base & APE1_FIXED_BITS_MASK) != 0)
+                       goto out;
+
+               if ((limit & APE1_FIXED_BITS_MASK) != APE1_LIMIT_ALIGNMENT)
+                       goto out;
+
+               qpd->sh_mem_ape1_base = base >> 16;
+               qpd->sh_mem_ape1_limit = limit >> 16;
+       }
+
+       default_mtype = (default_policy == cache_policy_coherent) ?
+                       MTYPE_NONCACHED :
+                       MTYPE_CACHED;
+
+       ape1_mtype = (alternate_policy == cache_policy_coherent) ?
+                       MTYPE_NONCACHED :
+                       MTYPE_CACHED;
+
+       qpd->sh_mem_config = (qpd->sh_mem_config & PTR32)
+                       | ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED)
+                       | DEFAULT_MTYPE(default_mtype)
+                       | APE1_MTYPE(ape1_mtype);
+
+       if ((sched_policy == KFD_SCHED_POLICY_NO_HWS) && (qpd->vmid != 0))
+               program_sh_mem_settings(dqm, qpd);
+
+       pr_debug("kfd: sh_mem_config: 0x%x, ape1_base: 0x%x, ape1_limit: 0x%x\n",
+               qpd->sh_mem_config, qpd->sh_mem_ape1_base,
+               qpd->sh_mem_ape1_limit);
+
+       mutex_unlock(&dqm->lock);
+       return true;
+
+out:
+       mutex_unlock(&dqm->lock);
+       return false;
+}
+
+struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev)
+{
+       struct device_queue_manager *dqm;
+
+       BUG_ON(!dev);
+
+       dqm = kzalloc(sizeof(struct device_queue_manager), GFP_KERNEL);
+       if (!dqm)
+               return NULL;
+
+       dqm->dev = dev;
+       switch (sched_policy) {
+       case KFD_SCHED_POLICY_HWS:
+       case KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION:
+               /* initialize dqm for cp scheduling */
+               dqm->create_queue = create_queue_cpsch;
+               dqm->initialize = initialize_cpsch;
+               dqm->start = start_cpsch;
+               dqm->stop = stop_cpsch;
+               dqm->destroy_queue = destroy_queue_cpsch;
+               dqm->update_queue = update_queue;
+               dqm->get_mqd_manager = get_mqd_manager_nocpsch;
+               dqm->register_process = register_process_nocpsch;
+               dqm->unregister_process = unregister_process_nocpsch;
+               dqm->uninitialize = uninitialize_nocpsch;
+               dqm->create_kernel_queue = create_kernel_queue_cpsch;
+               dqm->destroy_kernel_queue = destroy_kernel_queue_cpsch;
+               dqm->set_cache_memory_policy = set_cache_memory_policy;
+               break;
+       case KFD_SCHED_POLICY_NO_HWS:
+               /* initialize dqm for no cp scheduling */
+               dqm->start = start_nocpsch;
+               dqm->stop = stop_nocpsch;
+               dqm->create_queue = create_queue_nocpsch;
+               dqm->destroy_queue = destroy_queue_nocpsch;
+               dqm->update_queue = update_queue;
+               dqm->get_mqd_manager = get_mqd_manager_nocpsch;
+               dqm->register_process = register_process_nocpsch;
+               dqm->unregister_process = unregister_process_nocpsch;
+               dqm->initialize = initialize_nocpsch;
+               dqm->uninitialize = uninitialize_nocpsch;
+               dqm->set_cache_memory_policy = set_cache_memory_policy;
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       if (dqm->initialize(dqm) != 0) {
+               kfree(dqm);
+               return NULL;
+       }
+
+       return dqm;
+}
+
+void device_queue_manager_uninit(struct device_queue_manager *dqm)
+{
+       BUG_ON(!dqm);
+
+       dqm->uninitialize(dqm);
+       kfree(dqm);
+}
+
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
new file mode 100644 (file)
index 0000000..c3f189e
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef KFD_DEVICE_QUEUE_MANAGER_H_
+#define KFD_DEVICE_QUEUE_MANAGER_H_
+
+#include <linux/rwsem.h>
+#include <linux/list.h>
+#include "kfd_priv.h"
+#include "kfd_mqd_manager.h"
+
+#define QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS       (500)
+#define QUEUES_PER_PIPE                                (8)
+#define PIPE_PER_ME_CP_SCHEDULING              (3)
+#define CIK_VMID_NUM                           (8)
+#define KFD_VMID_START_OFFSET                  (8)
+#define VMID_PER_DEVICE                                CIK_VMID_NUM
+#define KFD_DQM_FIRST_PIPE                     (0)
+
+struct device_process_node {
+       struct qcm_process_device *qpd;
+       struct list_head list;
+};
+
+/**
+ * struct device_queue_manager
+ *
+ * @create_queue: Queue creation routine.
+ *
+ * @destroy_queue: Queue destruction routine.
+ *
+ * @update_queue: Queue update routine.
+ *
+ * @get_mqd_manager: Returns the mqd manager according to the mqd type.
+ *
+ * @exeute_queues: Dispatches the queues list to the H/W.
+ *
+ * @register_process: This routine associates a specific process with device.
+ *
+ * @unregister_process: destroys the associations between process to device.
+ *
+ * @initialize: Initializes the pipelines and memory module for that device.
+ *
+ * @start: Initializes the resources/modules the the device needs for queues
+ * execution. This function is called on device initialization and after the
+ * system woke up after suspension.
+ *
+ * @stop: This routine stops execution of all the active queue running on the
+ * H/W and basically this function called on system suspend.
+ *
+ * @uninitialize: Destroys all the device queue manager resources allocated in
+ * initialize routine.
+ *
+ * @create_kernel_queue: Creates kernel queue. Used for debug queue.
+ *
+ * @destroy_kernel_queue: Destroys kernel queue. Used for debug queue.
+ *
+ * @set_cache_memory_policy: Sets memory policy (cached/ non cached) for the
+ * memory apertures.
+ *
+ * This struct is a base class for the kfd queues scheduler in the
+ * device level. The device base class should expose the basic operations
+ * for queue creation and queue destruction. This base class hides the
+ * scheduling mode of the driver and the specific implementation of the
+ * concrete device. This class is the only class in the queues scheduler
+ * that configures the H/W.
+ */
+
+struct device_queue_manager {
+       int     (*create_queue)(struct device_queue_manager *dqm,
+                               struct queue *q,
+                               struct qcm_process_device *qpd,
+                               int *allocate_vmid);
+       int     (*destroy_queue)(struct device_queue_manager *dqm,
+                               struct qcm_process_device *qpd,
+                               struct queue *q);
+       int     (*update_queue)(struct device_queue_manager *dqm,
+                               struct queue *q);
+
+       struct mqd_manager * (*get_mqd_manager)
+                                       (struct device_queue_manager *dqm,
+                                       enum KFD_MQD_TYPE type);
+
+       int     (*register_process)(struct device_queue_manager *dqm,
+                                       struct qcm_process_device *qpd);
+       int     (*unregister_process)(struct device_queue_manager *dqm,
+                                       struct qcm_process_device *qpd);
+       int     (*initialize)(struct device_queue_manager *dqm);
+       int     (*start)(struct device_queue_manager *dqm);
+       int     (*stop)(struct device_queue_manager *dqm);
+       void    (*uninitialize)(struct device_queue_manager *dqm);
+       int     (*create_kernel_queue)(struct device_queue_manager *dqm,
+                                       struct kernel_queue *kq,
+                                       struct qcm_process_device *qpd);
+       void    (*destroy_kernel_queue)(struct device_queue_manager *dqm,
+                                       struct kernel_queue *kq,
+                                       struct qcm_process_device *qpd);
+       bool    (*set_cache_memory_policy)(struct device_queue_manager *dqm,
+                                          struct qcm_process_device *qpd,
+                                          enum cache_policy default_policy,
+                                          enum cache_policy alternate_policy,
+                                          void __user *alternate_aperture_base,
+                                          uint64_t alternate_aperture_size);
+
+
+       struct mqd_manager      *mqds[KFD_MQD_TYPE_MAX];
+       struct packet_manager   packets;
+       struct kfd_dev          *dev;
+       struct mutex            lock;
+       struct list_head        queues;
+       unsigned int            processes_count;
+       unsigned int            queue_count;
+       unsigned int            next_pipe_to_allocate;
+       unsigned int            *allocated_queues;
+       unsigned int            vmid_bitmap;
+       uint64_t                pipelines_addr;
+       struct kfd_mem_obj      *pipeline_mem;
+       uint64_t                fence_gpu_addr;
+       unsigned int            *fence_addr;
+       struct kfd_mem_obj      *fence_mem;
+       bool                    active_runlist;
+};
+
+
+
+#endif /* KFD_DEVICE_QUEUE_MANAGER_H_ */
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
new file mode 100644 (file)
index 0000000..b5791a5
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "kfd_priv.h"
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+/*
+ * This extension supports a kernel level doorbells management for
+ * the kernel queues.
+ * Basically the last doorbells page is devoted to kernel queues
+ * and that's assures that any user process won't get access to the
+ * kernel doorbells page
+ */
+static DEFINE_MUTEX(doorbell_mutex);
+static unsigned long doorbell_available_index[
+       DIV_ROUND_UP(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS, BITS_PER_LONG)] = { 0 };
+
+#define KERNEL_DOORBELL_PASID 1
+#define KFD_SIZE_OF_DOORBELL_IN_BYTES 4
+
+/*
+ * Each device exposes a doorbell aperture, a PCI MMIO aperture that
+ * receives 32-bit writes that are passed to queues as wptr values.
+ * The doorbells are intended to be written by applications as part
+ * of queueing work on user-mode queues.
+ * We assign doorbells to applications in PAGE_SIZE-sized and aligned chunks.
+ * We map the doorbell address space into user-mode when a process creates
+ * its first queue on each device.
+ * Although the mapping is done by KFD, it is equivalent to an mmap of
+ * the /dev/kfd with the particular device encoded in the mmap offset.
+ * There will be other uses for mmap of /dev/kfd, so only a range of
+ * offsets (KFD_MMAP_DOORBELL_START-END) is used for doorbells.
+ */
+
+/* # of doorbell bytes allocated for each process. */
+static inline size_t doorbell_process_allocation(void)
+{
+       return roundup(KFD_SIZE_OF_DOORBELL_IN_BYTES *
+                       KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
+                       PAGE_SIZE);
+}
+
+/* Doorbell calculations for device init. */
+void kfd_doorbell_init(struct kfd_dev *kfd)
+{
+       size_t doorbell_start_offset;
+       size_t doorbell_aperture_size;
+       size_t doorbell_process_limit;
+
+       /*
+        * We start with calculations in bytes because the input data might
+        * only be byte-aligned.
+        * Only after we have done the rounding can we assume any alignment.
+        */
+
+       doorbell_start_offset =
+                       roundup(kfd->shared_resources.doorbell_start_offset,
+                                       doorbell_process_allocation());
+
+       doorbell_aperture_size =
+                       rounddown(kfd->shared_resources.doorbell_aperture_size,
+                                       doorbell_process_allocation());
+
+       if (doorbell_aperture_size > doorbell_start_offset)
+               doorbell_process_limit =
+                       (doorbell_aperture_size - doorbell_start_offset) /
+                                               doorbell_process_allocation();
+       else
+               doorbell_process_limit = 0;
+
+       kfd->doorbell_base = kfd->shared_resources.doorbell_physical_address +
+                               doorbell_start_offset;
+
+       kfd->doorbell_id_offset = doorbell_start_offset / sizeof(u32);
+       kfd->doorbell_process_limit = doorbell_process_limit - 1;
+
+       kfd->doorbell_kernel_ptr = ioremap(kfd->doorbell_base,
+                                               doorbell_process_allocation());
+
+       BUG_ON(!kfd->doorbell_kernel_ptr);
+
+       pr_debug("kfd: doorbell initialization:\n");
+       pr_debug("kfd: doorbell base           == 0x%08lX\n",
+                       (uintptr_t)kfd->doorbell_base);
+
+       pr_debug("kfd: doorbell_id_offset      == 0x%08lX\n",
+                       kfd->doorbell_id_offset);
+
+       pr_debug("kfd: doorbell_process_limit  == 0x%08lX\n",
+                       doorbell_process_limit);
+
+       pr_debug("kfd: doorbell_kernel_offset  == 0x%08lX\n",
+                       (uintptr_t)kfd->doorbell_base);
+
+       pr_debug("kfd: doorbell aperture size  == 0x%08lX\n",
+                       kfd->shared_resources.doorbell_aperture_size);
+
+       pr_debug("kfd: doorbell kernel address == 0x%08lX\n",
+                       (uintptr_t)kfd->doorbell_kernel_ptr);
+}
+
+int kfd_doorbell_mmap(struct kfd_process *process, struct vm_area_struct *vma)
+{
+       phys_addr_t address;
+       struct kfd_dev *dev;
+
+       /*
+        * For simplicitly we only allow mapping of the entire doorbell
+        * allocation of a single device & process.
+        */
+       if (vma->vm_end - vma->vm_start != doorbell_process_allocation())
+               return -EINVAL;
+
+       /* Find kfd device according to gpu id */
+       dev = kfd_device_by_id(vma->vm_pgoff);
+       if (dev == NULL)
+               return -EINVAL;
+
+       /* Find if pdd exists for combination of process and gpu id */
+       if (!kfd_get_process_device_data(dev, process, 0))
+               return -EINVAL;
+
+       /* Calculate physical address of doorbell */
+       address = kfd_get_process_doorbells(dev, process);
+
+       vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_NORESERVE |
+                               VM_DONTDUMP | VM_PFNMAP;
+
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+       pr_debug("kfd: mapping doorbell page in kfd_doorbell_mmap\n"
+                "     target user address == 0x%08llX\n"
+                "     physical address    == 0x%08llX\n"
+                "     vm_flags            == 0x%04lX\n"
+                "     size                == 0x%04lX\n",
+                (unsigned long long) vma->vm_start, address, vma->vm_flags,
+                doorbell_process_allocation());
+
+
+       return io_remap_pfn_range(vma,
+                               vma->vm_start,
+                               address >> PAGE_SHIFT,
+                               doorbell_process_allocation(),
+                               vma->vm_page_prot);
+}
+
+
+/* get kernel iomem pointer for a doorbell */
+u32 __iomem *kfd_get_kernel_doorbell(struct kfd_dev *kfd,
+                                       unsigned int *doorbell_off)
+{
+       u32 inx;
+
+       BUG_ON(!kfd || !doorbell_off);
+
+       mutex_lock(&doorbell_mutex);
+       inx = find_first_zero_bit(doorbell_available_index,
+                                       KFD_MAX_NUM_OF_QUEUES_PER_PROCESS);
+
+       __set_bit(inx, doorbell_available_index);
+       mutex_unlock(&doorbell_mutex);
+
+       if (inx >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)
+               return NULL;
+
+       /*
+        * Calculating the kernel doorbell offset using "faked" kernel
+        * pasid that allocated for kernel queues only
+        */
+       *doorbell_off = KERNEL_DOORBELL_PASID * (doorbell_process_allocation() /
+                                                       sizeof(u32)) + inx;
+
+       pr_debug("kfd: get kernel queue doorbell\n"
+                        "     doorbell offset   == 0x%08d\n"
+                        "     kernel address    == 0x%08lX\n",
+               *doorbell_off, (uintptr_t)(kfd->doorbell_kernel_ptr + inx));
+
+       return kfd->doorbell_kernel_ptr + inx;
+}
+
+void kfd_release_kernel_doorbell(struct kfd_dev *kfd, u32 __iomem *db_addr)
+{
+       unsigned int inx;
+
+       BUG_ON(!kfd || !db_addr);
+
+       inx = (unsigned int)(db_addr - kfd->doorbell_kernel_ptr);
+
+       mutex_lock(&doorbell_mutex);
+       __clear_bit(inx, doorbell_available_index);
+       mutex_unlock(&doorbell_mutex);
+}
+
+inline void write_kernel_doorbell(u32 __iomem *db, u32 value)
+{
+       if (db) {
+               writel(value, db);
+               pr_debug("writing %d to doorbell address 0x%p\n", value, db);
+       }
+}
+
+/*
+ * queue_ids are in the range [0,MAX_PROCESS_QUEUES) and are mapped 1:1
+ * to doorbells with the process's doorbell page
+ */
+unsigned int kfd_queue_id_to_doorbell(struct kfd_dev *kfd,
+                                       struct kfd_process *process,
+                                       unsigned int queue_id)
+{
+       /*
+        * doorbell_id_offset accounts for doorbells taken by KGD.
+        * pasid * doorbell_process_allocation/sizeof(u32) adjusts
+        * to the process's doorbells
+        */
+       return kfd->doorbell_id_offset +
+               process->pasid * (doorbell_process_allocation()/sizeof(u32)) +
+               queue_id;
+}
+
+uint64_t kfd_get_number_elems(struct kfd_dev *kfd)
+{
+       uint64_t num_of_elems = (kfd->shared_resources.doorbell_aperture_size -
+                               kfd->shared_resources.doorbell_start_offset) /
+                                       doorbell_process_allocation() + 1;
+
+       return num_of_elems;
+
+}
+
+phys_addr_t kfd_get_process_doorbells(struct kfd_dev *dev,
+                                       struct kfd_process *process)
+{
+       return dev->doorbell_base +
+               process->pasid * doorbell_process_allocation();
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c
new file mode 100644 (file)
index 0000000..66df4da
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/compat.h>
+#include <uapi/linux/kfd_ioctl.h>
+#include <linux/time.h>
+#include "kfd_priv.h"
+#include <linux/mm.h>
+#include <uapi/asm-generic/mman-common.h>
+#include <asm/processor.h>
+
+/*
+ * The primary memory I/O features being added for revisions of gfxip
+ * beyond 7.0 (Kaveri) are:
+ *
+ * Access to ATC/IOMMU mapped memory w/ associated extension of VA to 48b
+ *
+ * “Flat” shader memory access – These are new shader vector memory
+ * operations that do not reference a T#/V# so a “pointer” is what is
+ * sourced from the vector gprs for direct access to memory.
+ * This pointer space has the Shared(LDS) and Private(Scratch) memory
+ * mapped into this pointer space as apertures.
+ * The hardware then determines how to direct the memory request
+ * based on what apertures the request falls in.
+ *
+ * Unaligned support and alignment check
+ *
+ *
+ * System Unified Address - SUA
+ *
+ * The standard usage for GPU virtual addresses are that they are mapped by
+ * a set of page tables we call GPUVM and these page tables are managed by
+ * a combination of vidMM/driver software components.  The current virtual
+ * address (VA) range for GPUVM is 40b.
+ *
+ * As of gfxip7.1 and beyond we’re adding the ability for compute memory
+ * clients (CP/RLC, DMA, SHADER(ifetch, scalar, and vector ops)) to access
+ * the same page tables used by host x86 processors and that are managed by
+ * the operating system. This is via a technique and hardware called ATC/IOMMU.
+ * The GPU has the capability of accessing both the GPUVM and ATC address
+ * spaces for a given VMID (process) simultaneously and we call this feature
+ * system unified address (SUA).
+ *
+ * There are three fundamental address modes of operation for a given VMID
+ * (process) on the GPU:
+ *
+ *     HSA64 – 64b pointers and the default address space is ATC
+ *     HSA32 – 32b pointers and the default address space is ATC
+ *     GPUVM – 64b pointers and the default address space is GPUVM (driver
+ *             model mode)
+ *
+ *
+ * HSA64 - ATC/IOMMU 64b
+ *
+ * A 64b pointer in the AMD64/IA64 CPU architecture is not fully utilized
+ * by the CPU so an AMD CPU can only access the high area
+ * (VA[63:47] == 0x1FFFF) and low area (VA[63:47 == 0) of the address space
+ * so the actual VA carried to translation is 48b.  There is a “hole” in
+ * the middle of the 64b VA space.
+ *
+ * The GPU not only has access to all of the CPU accessible address space via
+ * ATC/IOMMU, but it also has access to the GPUVM address space.  The “system
+ * unified address” feature (SUA) is the mapping of GPUVM and ATC address
+ * spaces into a unified pointer space.  The method we take for 64b mode is
+ * to map the full 40b GPUVM address space into the hole of the 64b address
+ * space.
+
+ * The GPUVM_Base/GPUVM_Limit defines the aperture in the 64b space where we
+ * direct requests to be translated via GPUVM page tables instead of the
+ * IOMMU path.
+ *
+ *
+ * 64b to 49b Address conversion
+ *
+ * Note that there are still significant portions of unused regions (holes)
+ * in the 64b address space even for the GPU.  There are several places in
+ * the pipeline (sw and hw), we wish to compress the 64b virtual address
+ * to a 49b address.  This 49b address is constituted of an “ATC” bit
+ * plus a 48b virtual address.  This 49b address is what is passed to the
+ * translation hardware.  ATC==0 means the 48b address is a GPUVM address
+ * (max of 2^40 – 1) intended to be translated via GPUVM page tables.
+ * ATC==1 means the 48b address is intended to be translated via IOMMU
+ * page tables.
+ *
+ * A 64b pointer is compared to the apertures that are defined (Base/Limit), in
+ * this case the GPUVM aperture (red) is defined and if a pointer falls in this
+ * aperture, we subtract the GPUVM_Base address and set the ATC bit to zero
+ * as part of the 64b to 49b conversion.
+ *
+ * Where this 64b to 49b conversion is done is a function of the usage.
+ * Most GPU memory access is via memory objects where the driver builds
+ * a descriptor which consists of a base address and a memory access by
+ * the GPU usually consists of some kind of an offset or Cartesian coordinate
+ * that references this memory descriptor.  This is the case for shader
+ * instructions that reference the T# or V# constants, or for specified
+ * locations of assets (ex. the shader program location).  In these cases
+ * the driver is what handles the 64b to 49b conversion and the base
+ * address in the descriptor (ex. V# or T# or shader program location)
+ * is defined as a 48b address w/ an ATC bit.  For this usage a given
+ * memory object cannot straddle multiple apertures in the 64b address
+ * space. For example a shader program cannot jump in/out between ATC
+ * and GPUVM space.
+ *
+ * In some cases we wish to pass a 64b pointer to the GPU hardware and
+ * the GPU hw does the 64b to 49b conversion before passing memory
+ * requests to the cache/memory system.  This is the case for the
+ * S_LOAD and FLAT_* shader memory instructions where we have 64b pointers
+ * in scalar and vector GPRs respectively.
+ *
+ * In all cases (no matter where the 64b -> 49b conversion is done), the gfxip
+ * hardware sends a 48b address along w/ an ATC bit, to the memory controller
+ * on the memory request interfaces.
+ *
+ *     <client>_MC_rdreq_atc   // read request ATC bit
+ *
+ *             0 : <client>_MC_rdreq_addr is a GPUVM VA
+ *
+ *             1 : <client>_MC_rdreq_addr is a ATC VA
+ *
+ *
+ * “Spare” aperture (APE1)
+ *
+ * We use the GPUVM aperture to differentiate ATC vs. GPUVM, but we also use
+ * apertures to set the Mtype field for S_LOAD/FLAT_* ops which is input to the
+ * config tables for setting cache policies. The “spare” (APE1) aperture is
+ * motivated by getting a different Mtype from the default.
+ * The default aperture isn’t an actual base/limit aperture; it is just the
+ * address space that doesn’t hit any defined base/limit apertures.
+ * The following diagram is a complete picture of the gfxip7.x SUA apertures.
+ * The APE1 can be placed either below or above
+ * the hole (cannot be in the hole).
+ *
+ *
+ * General Aperture definitions and rules
+ *
+ * An aperture register definition consists of a Base, Limit, Mtype, and
+ * usually an ATC bit indicating which translation tables that aperture uses.
+ * In all cases (for SUA and DUA apertures discussed later), aperture base
+ * and limit definitions are 64KB aligned.
+ *
+ *     <ape>_Base[63:0] = { <ape>_Base_register[63:16], 0x0000 }
+ *
+ *     <ape>_Limit[63:0] = { <ape>_Limit_register[63:16], 0xFFFF }
+ *
+ * The base and limit are considered inclusive to an aperture so being
+ * inside an aperture means (address >= Base) AND (address <= Limit).
+ *
+ * In no case is a payload that straddles multiple apertures expected to work.
+ * For example a load_dword_x4 that starts in one aperture and ends in another,
+ * does not work.  For the vector FLAT_* ops we have detection capability in
+ * the shader for reporting a “memory violation” back to the
+ * SQ block for use in traps.
+ * A memory violation results when an op falls into the hole,
+ * or a payload straddles multiple apertures.  The S_LOAD instruction
+ * does not have this detection.
+ *
+ * Apertures cannot overlap.
+ *
+ *
+ *
+ * HSA32 - ATC/IOMMU 32b
+ *
+ * For HSA32 mode, the pointers are interpreted as 32 bits and use a single GPR
+ * instead of two for the S_LOAD and FLAT_* ops. The entire GPUVM space of 40b
+ * will not fit so there is only partial visibility to the GPUVM
+ * space (defined by the aperture) for S_LOAD and FLAT_* ops.
+ * There is no spare (APE1) aperture for HSA32 mode.
+ *
+ *
+ * GPUVM 64b mode (driver model)
+ *
+ * This mode is related to HSA64 in that the difference really is that
+ * the default aperture is GPUVM (ATC==0) and not ATC space.
+ * We have gfxip7.x hardware that has FLAT_* and S_LOAD support for
+ * SUA GPUVM mode, but does not support HSA32/HSA64.
+ *
+ *
+ * Device Unified Address - DUA
+ *
+ * Device unified address (DUA) is the name of the feature that maps the
+ * Shared(LDS) memory and Private(Scratch) memory into the overall address
+ * space for use by the new FLAT_* vector memory ops.  The Shared and
+ * Private memories are mapped as apertures into the address space,
+ * and the hardware detects when a FLAT_* memory request is to be redirected
+ * to the LDS or Scratch memory when it falls into one of these apertures.
+ * Like the SUA apertures, the Shared/Private apertures are 64KB aligned and
+ * the base/limit is “in” the aperture. For both HSA64 and GPUVM SUA modes,
+ * the Shared/Private apertures are always placed in a limited selection of
+ * options in the hole of the 64b address space. For HSA32 mode, the
+ * Shared/Private apertures can be placed anywhere in the 32b space
+ * except at 0.
+ *
+ *
+ * HSA64 Apertures for FLAT_* vector ops
+ *
+ * For HSA64 SUA mode, the Shared and Private apertures are always placed
+ * in the hole w/ a limited selection of possible locations. The requests
+ * that fall in the private aperture are expanded as a function of the
+ * work-item id (tid) and redirected to the location of the
+ * “hidden private memory”. The hidden private can be placed in either GPUVM
+ * or ATC space. The addresses that fall in the shared aperture are
+ * re-directed to the on-chip LDS memory hardware.
+ *
+ *
+ * HSA32 Apertures for FLAT_* vector ops
+ *
+ * In HSA32 mode, the Private and Shared apertures can be placed anywhere
+ * in the 32b space except at 0 (Private or Shared Base at zero disables
+ * the apertures). If the base address of the apertures are non-zero
+ * (ie apertures exists), the size is always 64KB.
+ *
+ *
+ * GPUVM Apertures for FLAT_* vector ops
+ *
+ * In GPUVM mode, the Shared/Private apertures are specified identically
+ * to HSA64 mode where they are always in the hole at a limited selection
+ * of locations.
+ *
+ *
+ * Aperture Definitions for SUA and DUA
+ *
+ * The interpretation of the aperture register definitions for a given
+ * VMID is a function of the “SUA Mode” which is one of HSA64, HSA32, or
+ * GPUVM64 discussed in previous sections. The mode is first decoded, and
+ * then the remaining register decode is a function of the mode.
+ *
+ *
+ * SUA Mode Decode
+ *
+ * For the S_LOAD and FLAT_* shader operations, the SUA mode is decoded from
+ * the COMPUTE_DISPATCH_INITIATOR:DATA_ATC bit and
+ * the SH_MEM_CONFIG:PTR32 bits.
+ *
+ * COMPUTE_DISPATCH_INITIATOR:DATA_ATC    SH_MEM_CONFIG:PTR32        Mode
+ *
+ * 1                                              0                  HSA64
+ *
+ * 1                                              1                  HSA32
+ *
+ * 0                                              X                 GPUVM64
+ *
+ * In general the hardware will ignore the PTR32 bit and treat
+ * as “0” whenever DATA_ATC = “0”, but sw should set PTR32=0
+ * when DATA_ATC=0.
+ *
+ * The DATA_ATC bit is only set for compute dispatches.
+ * All “Draw” dispatches are hardcoded to GPUVM64 mode
+ * for FLAT_* / S_LOAD operations.
+ */
+
+#define MAKE_GPUVM_APP_BASE(gpu_num) \
+       (((uint64_t)(gpu_num) << 61) + 0x1000000000000L)
+
+#define MAKE_GPUVM_APP_LIMIT(base) \
+       (((uint64_t)(base) & \
+               0xFFFFFF0000000000UL) | 0xFFFFFFFFFFL)
+
+#define MAKE_SCRATCH_APP_BASE(gpu_num) \
+       (((uint64_t)(gpu_num) << 61) + 0x100000000L)
+
+#define MAKE_SCRATCH_APP_LIMIT(base) \
+       (((uint64_t)base & 0xFFFFFFFF00000000UL) | 0xFFFFFFFF)
+
+#define MAKE_LDS_APP_BASE(gpu_num) \
+       (((uint64_t)(gpu_num) << 61) + 0x0)
+#define MAKE_LDS_APP_LIMIT(base) \
+       (((uint64_t)(base) & 0xFFFFFFFF00000000UL) | 0xFFFFFFFF)
+
+int kfd_init_apertures(struct kfd_process *process)
+{
+       uint8_t id  = 0;
+       struct kfd_dev *dev;
+       struct kfd_process_device *pdd;
+
+       mutex_lock(&process->mutex);
+
+       /*Iterating over all devices*/
+       while ((dev = kfd_topology_enum_kfd_devices(id)) != NULL &&
+               id < NUM_OF_SUPPORTED_GPUS) {
+
+               pdd = kfd_get_process_device_data(dev, process, 1);
+
+               /*
+                * For 64 bit process aperture will be statically reserved in
+                * the x86_64 non canonical process address space
+                * amdkfd doesn't currently support apertures for 32 bit process
+                */
+               if (process->is_32bit_user_mode) {
+                       pdd->lds_base = pdd->lds_limit = 0;
+                       pdd->gpuvm_base = pdd->gpuvm_limit = 0;
+                       pdd->scratch_base = pdd->scratch_limit = 0;
+               } else {
+                       /*
+                        * node id couldn't be 0 - the three MSB bits of
+                        * aperture shoudn't be 0
+                        */
+                       pdd->lds_base = MAKE_LDS_APP_BASE(id + 1);
+
+                       pdd->lds_limit = MAKE_LDS_APP_LIMIT(pdd->lds_base);
+
+                       pdd->gpuvm_base = MAKE_GPUVM_APP_BASE(id + 1);
+
+                       pdd->gpuvm_limit =
+                                       MAKE_GPUVM_APP_LIMIT(pdd->gpuvm_base);
+
+                       pdd->scratch_base = MAKE_SCRATCH_APP_BASE(id + 1);
+
+                       pdd->scratch_limit =
+                               MAKE_SCRATCH_APP_LIMIT(pdd->scratch_base);
+               }
+
+               dev_dbg(kfd_device, "node id %u\n", id);
+               dev_dbg(kfd_device, "gpu id %u\n", pdd->dev->id);
+               dev_dbg(kfd_device, "lds_base %llX\n", pdd->lds_base);
+               dev_dbg(kfd_device, "lds_limit %llX\n", pdd->lds_limit);
+               dev_dbg(kfd_device, "gpuvm_base %llX\n", pdd->gpuvm_base);
+               dev_dbg(kfd_device, "gpuvm_limit %llX\n", pdd->gpuvm_limit);
+               dev_dbg(kfd_device, "scratch_base %llX\n", pdd->scratch_base);
+               dev_dbg(kfd_device, "scratch_limit %llX\n", pdd->scratch_limit);
+
+               id++;
+       }
+
+       mutex_unlock(&process->mutex);
+
+       return 0;
+}
+
+
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c b/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c
new file mode 100644 (file)
index 0000000..5b99909
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * KFD Interrupts.
+ *
+ * AMD GPUs deliver interrupts by pushing an interrupt description onto the
+ * interrupt ring and then sending an interrupt. KGD receives the interrupt
+ * in ISR and sends us a pointer to each new entry on the interrupt ring.
+ *
+ * We generally can't process interrupt-signaled events from ISR, so we call
+ * out to each interrupt client module (currently only the scheduler) to ask if
+ * each interrupt is interesting. If they return true, then it requires further
+ * processing so we copy it to an internal interrupt ring and call each
+ * interrupt client again from a work-queue.
+ *
+ * There's no acknowledgment for the interrupts we use. The hardware simply
+ * queues a new interrupt each time without waiting.
+ *
+ * The fixed-size internal queue means that it's possible for us to lose
+ * interrupts because we have no back-pressure to the hardware.
+ */
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include "kfd_priv.h"
+
+#define KFD_INTERRUPT_RING_SIZE 256
+
+static void interrupt_wq(struct work_struct *);
+
+int kfd_interrupt_init(struct kfd_dev *kfd)
+{
+       void *interrupt_ring = kmalloc_array(KFD_INTERRUPT_RING_SIZE,
+                                       kfd->device_info->ih_ring_entry_size,
+                                       GFP_KERNEL);
+       if (!interrupt_ring)
+               return -ENOMEM;
+
+       kfd->interrupt_ring = interrupt_ring;
+       kfd->interrupt_ring_size =
+               KFD_INTERRUPT_RING_SIZE * kfd->device_info->ih_ring_entry_size;
+       atomic_set(&kfd->interrupt_ring_wptr, 0);
+       atomic_set(&kfd->interrupt_ring_rptr, 0);
+
+       spin_lock_init(&kfd->interrupt_lock);
+
+       INIT_WORK(&kfd->interrupt_work, interrupt_wq);
+
+       kfd->interrupts_active = true;
+
+       /*
+        * After this function returns, the interrupt will be enabled. This
+        * barrier ensures that the interrupt running on a different processor
+        * sees all the above writes.
+        */
+       smp_wmb();
+
+       return 0;
+}
+
+void kfd_interrupt_exit(struct kfd_dev *kfd)
+{
+       /*
+        * Stop the interrupt handler from writing to the ring and scheduling
+        * workqueue items. The spinlock ensures that any interrupt running
+        * after we have unlocked sees interrupts_active = false.
+        */
+       unsigned long flags;
+
+       spin_lock_irqsave(&kfd->interrupt_lock, flags);
+       kfd->interrupts_active = false;
+       spin_unlock_irqrestore(&kfd->interrupt_lock, flags);
+
+       /*
+        * Flush_scheduled_work ensures that there are no outstanding
+        * work-queue items that will access interrupt_ring. New work items
+        * can't be created because we stopped interrupt handling above.
+        */
+       flush_scheduled_work();
+
+       kfree(kfd->interrupt_ring);
+}
+
+/*
+ * This assumes that it can't be called concurrently with itself
+ * but only with dequeue_ih_ring_entry.
+ */
+bool enqueue_ih_ring_entry(struct kfd_dev *kfd,        const void *ih_ring_entry)
+{
+       unsigned int rptr = atomic_read(&kfd->interrupt_ring_rptr);
+       unsigned int wptr = atomic_read(&kfd->interrupt_ring_wptr);
+
+       if ((rptr - wptr) % kfd->interrupt_ring_size ==
+                                       kfd->device_info->ih_ring_entry_size) {
+               /* This is very bad, the system is likely to hang. */
+               dev_err_ratelimited(kfd_chardev(),
+                       "Interrupt ring overflow, dropping interrupt.\n");
+               return false;
+       }
+
+       memcpy(kfd->interrupt_ring + wptr, ih_ring_entry,
+                       kfd->device_info->ih_ring_entry_size);
+
+       wptr = (wptr + kfd->device_info->ih_ring_entry_size) %
+                       kfd->interrupt_ring_size;
+       smp_wmb(); /* Ensure memcpy'd data is visible before wptr update. */
+       atomic_set(&kfd->interrupt_ring_wptr, wptr);
+
+       return true;
+}
+
+/*
+ * This assumes that it can't be called concurrently with itself
+ * but only with enqueue_ih_ring_entry.
+ */
+static bool dequeue_ih_ring_entry(struct kfd_dev *kfd, void *ih_ring_entry)
+{
+       /*
+        * Assume that wait queues have an implicit barrier, i.e. anything that
+        * happened in the ISR before it queued work is visible.
+        */
+
+       unsigned int wptr = atomic_read(&kfd->interrupt_ring_wptr);
+       unsigned int rptr = atomic_read(&kfd->interrupt_ring_rptr);
+
+       if (rptr == wptr)
+               return false;
+
+       memcpy(ih_ring_entry, kfd->interrupt_ring + rptr,
+                       kfd->device_info->ih_ring_entry_size);
+
+       rptr = (rptr + kfd->device_info->ih_ring_entry_size) %
+                       kfd->interrupt_ring_size;
+
+       /*
+        * Ensure the rptr write update is not visible until
+        * memcpy has finished reading.
+        */
+       smp_mb();
+       atomic_set(&kfd->interrupt_ring_rptr, rptr);
+
+       return true;
+}
+
+static void interrupt_wq(struct work_struct *work)
+{
+       struct kfd_dev *dev = container_of(work, struct kfd_dev,
+                                               interrupt_work);
+
+       uint32_t ih_ring_entry[DIV_ROUND_UP(
+                               dev->device_info->ih_ring_entry_size,
+                               sizeof(uint32_t))];
+
+       while (dequeue_ih_ring_entry(dev, ih_ring_entry))
+               ;
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c
new file mode 100644 (file)
index 0000000..9abac48
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/printk.h>
+#include <linux/sched.h>
+#include "kfd_kernel_queue.h"
+#include "kfd_priv.h"
+#include "kfd_device_queue_manager.h"
+#include "kfd_pm4_headers.h"
+#include "kfd_pm4_opcodes.h"
+
+#define PM4_COUNT_ZERO (((1 << 15) - 1) << 16)
+
+static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
+               enum kfd_queue_type type, unsigned int queue_size)
+{
+       struct queue_properties prop;
+       int retval;
+       union PM4_MES_TYPE_3_HEADER nop;
+
+       BUG_ON(!kq || !dev);
+       BUG_ON(type != KFD_QUEUE_TYPE_DIQ && type != KFD_QUEUE_TYPE_HIQ);
+
+       pr_debug("kfd: In func %s initializing queue type %d size %d\n",
+                       __func__, KFD_QUEUE_TYPE_HIQ, queue_size);
+
+       nop.opcode = IT_NOP;
+       nop.type = PM4_TYPE_3;
+       nop.u32all |= PM4_COUNT_ZERO;
+
+       kq->dev = dev;
+       kq->nop_packet = nop.u32all;
+       switch (type) {
+       case KFD_QUEUE_TYPE_DIQ:
+       case KFD_QUEUE_TYPE_HIQ:
+               kq->mqd = dev->dqm->get_mqd_manager(dev->dqm,
+                                               KFD_MQD_TYPE_CIK_HIQ);
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       if (kq->mqd == NULL)
+               return false;
+
+       prop.doorbell_ptr = kfd_get_kernel_doorbell(dev, &prop.doorbell_off);
+
+       if (prop.doorbell_ptr == NULL)
+               goto err_get_kernel_doorbell;
+
+       retval = kfd2kgd->allocate_mem(dev->kgd,
+                                       queue_size,
+                                       PAGE_SIZE,
+                                       KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
+                                       (struct kgd_mem **) &kq->pq);
+
+       if (retval != 0)
+               goto err_pq_allocate_vidmem;
+
+       kq->pq_kernel_addr = kq->pq->cpu_ptr;
+       kq->pq_gpu_addr = kq->pq->gpu_addr;
+
+       retval = kfd2kgd->allocate_mem(dev->kgd,
+                                       sizeof(*kq->rptr_kernel),
+                                       32,
+                                       KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
+                                       (struct kgd_mem **) &kq->rptr_mem);
+
+       if (retval != 0)
+               goto err_rptr_allocate_vidmem;
+
+       kq->rptr_kernel = kq->rptr_mem->cpu_ptr;
+       kq->rptr_gpu_addr = kq->rptr_mem->gpu_addr;
+
+       retval = kfd2kgd->allocate_mem(dev->kgd,
+                                       sizeof(*kq->wptr_kernel),
+                                       32,
+                                       KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
+                                       (struct kgd_mem **) &kq->wptr_mem);
+
+       if (retval != 0)
+               goto err_wptr_allocate_vidmem;
+
+       kq->wptr_kernel = kq->wptr_mem->cpu_ptr;
+       kq->wptr_gpu_addr = kq->wptr_mem->gpu_addr;
+
+       memset(kq->pq_kernel_addr, 0, queue_size);
+       memset(kq->rptr_kernel, 0, sizeof(*kq->rptr_kernel));
+       memset(kq->wptr_kernel, 0, sizeof(*kq->wptr_kernel));
+
+       prop.queue_size = queue_size;
+       prop.is_interop = false;
+       prop.priority = 1;
+       prop.queue_percent = 100;
+       prop.type = type;
+       prop.vmid = 0;
+       prop.queue_address = kq->pq_gpu_addr;
+       prop.read_ptr = (uint32_t *) kq->rptr_gpu_addr;
+       prop.write_ptr = (uint32_t *) kq->wptr_gpu_addr;
+
+       if (init_queue(&kq->queue, prop) != 0)
+               goto err_init_queue;
+
+       kq->queue->device = dev;
+       kq->queue->process = kfd_get_process(current);
+
+       retval = kq->mqd->init_mqd(kq->mqd, &kq->queue->mqd,
+                                       &kq->queue->mqd_mem_obj,
+                                       &kq->queue->gart_mqd_addr,
+                                       &kq->queue->properties);
+       if (retval != 0)
+               goto err_init_mqd;
+
+       /* assign HIQ to HQD */
+       if (type == KFD_QUEUE_TYPE_HIQ) {
+               pr_debug("assigning hiq to hqd\n");
+               kq->queue->pipe = KFD_CIK_HIQ_PIPE;
+               kq->queue->queue = KFD_CIK_HIQ_QUEUE;
+               kq->mqd->load_mqd(kq->mqd, kq->queue->mqd, kq->queue->pipe,
+                                       kq->queue->queue, NULL);
+       } else {
+               /* allocate fence for DIQ */
+
+               retval = kfd2kgd->allocate_mem(dev->kgd,
+                                       sizeof(uint32_t),
+                                       32,
+                                       KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
+                                       (struct kgd_mem **) &kq->fence_mem_obj);
+
+               if (retval != 0)
+                       goto err_alloc_fence;
+
+               kq->fence_kernel_address = kq->fence_mem_obj->cpu_ptr;
+               kq->fence_gpu_addr = kq->fence_mem_obj->gpu_addr;
+       }
+
+       print_queue(kq->queue);
+
+       return true;
+err_alloc_fence:
+err_init_mqd:
+       uninit_queue(kq->queue);
+err_init_queue:
+       kfd2kgd->free_mem(dev->kgd, (struct kgd_mem *) kq->wptr_mem);
+err_wptr_allocate_vidmem:
+       kfd2kgd->free_mem(dev->kgd, (struct kgd_mem *) kq->rptr_mem);
+err_rptr_allocate_vidmem:
+       kfd2kgd->free_mem(dev->kgd, (struct kgd_mem *) kq->pq);
+err_pq_allocate_vidmem:
+       pr_err("kfd: error init pq\n");
+       kfd_release_kernel_doorbell(dev, prop.doorbell_ptr);
+err_get_kernel_doorbell:
+       pr_err("kfd: error init doorbell");
+       return false;
+
+}
+
+static void uninitialize(struct kernel_queue *kq)
+{
+       BUG_ON(!kq);
+
+       if (kq->queue->properties.type == KFD_QUEUE_TYPE_HIQ)
+               kq->mqd->destroy_mqd(kq->mqd,
+                                       NULL,
+                                       false,
+                                       QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS,
+                                       kq->queue->pipe,
+                                       kq->queue->queue);
+
+       kfd2kgd->free_mem(kq->dev->kgd, (struct kgd_mem *) kq->rptr_mem);
+       kfd2kgd->free_mem(kq->dev->kgd, (struct kgd_mem *) kq->wptr_mem);
+       kfd2kgd->free_mem(kq->dev->kgd, (struct kgd_mem *) kq->pq);
+       kfd_release_kernel_doorbell(kq->dev,
+                                       kq->queue->properties.doorbell_ptr);
+       uninit_queue(kq->queue);
+}
+
+static int acquire_packet_buffer(struct kernel_queue *kq,
+               size_t packet_size_in_dwords, unsigned int **buffer_ptr)
+{
+       size_t available_size;
+       size_t queue_size_dwords;
+       uint32_t wptr, rptr;
+       unsigned int *queue_address;
+
+       BUG_ON(!kq || !buffer_ptr);
+
+       rptr = *kq->rptr_kernel;
+       wptr = *kq->wptr_kernel;
+       queue_address = (unsigned int *)kq->pq_kernel_addr;
+       queue_size_dwords = kq->queue->properties.queue_size / sizeof(uint32_t);
+
+       pr_debug("kfd: In func %s\nrptr: %d\nwptr: %d\nqueue_address 0x%p\n",
+                       __func__, rptr, wptr, queue_address);
+
+       available_size = (rptr - 1 - wptr + queue_size_dwords) %
+                                                       queue_size_dwords;
+
+       if (packet_size_in_dwords >= queue_size_dwords ||
+                       packet_size_in_dwords >= available_size)
+               return -ENOMEM;
+
+       if (wptr + packet_size_in_dwords >= queue_size_dwords) {
+               while (wptr > 0) {
+                       queue_address[wptr] = kq->nop_packet;
+                       wptr = (wptr + 1) % queue_size_dwords;
+               }
+       }
+
+       *buffer_ptr = &queue_address[wptr];
+       kq->pending_wptr = wptr + packet_size_in_dwords;
+
+       return 0;
+}
+
+static void submit_packet(struct kernel_queue *kq)
+{
+#ifdef DEBUG
+       int i;
+#endif
+
+       BUG_ON(!kq);
+
+#ifdef DEBUG
+       for (i = *kq->wptr_kernel; i < kq->pending_wptr; i++) {
+               pr_debug("0x%2X ", kq->pq_kernel_addr[i]);
+               if (i % 15 == 0)
+                       pr_debug("\n");
+       }
+       pr_debug("\n");
+#endif
+
+       *kq->wptr_kernel = kq->pending_wptr;
+       write_kernel_doorbell(kq->queue->properties.doorbell_ptr,
+                               kq->pending_wptr);
+}
+
+static int sync_with_hw(struct kernel_queue *kq, unsigned long timeout_ms)
+{
+       unsigned long org_timeout_ms;
+
+       BUG_ON(!kq);
+
+       org_timeout_ms = timeout_ms;
+       timeout_ms += jiffies * 1000 / HZ;
+       while (*kq->wptr_kernel != *kq->rptr_kernel) {
+               if (time_after(jiffies * 1000 / HZ, timeout_ms)) {
+                       pr_err("kfd: kernel_queue %s timeout expired %lu\n",
+                               __func__, org_timeout_ms);
+                       pr_err("kfd: wptr: %d rptr: %d\n",
+                               *kq->wptr_kernel, *kq->rptr_kernel);
+                       return -ETIME;
+               }
+               schedule();
+       }
+
+       return 0;
+}
+
+static void rollback_packet(struct kernel_queue *kq)
+{
+       BUG_ON(!kq);
+       kq->pending_wptr = *kq->queue->properties.write_ptr;
+}
+
+struct kernel_queue *kernel_queue_init(struct kfd_dev *dev,
+                                       enum kfd_queue_type type)
+{
+       struct kernel_queue *kq;
+
+       BUG_ON(!dev);
+
+       kq = kzalloc(sizeof(struct kernel_queue), GFP_KERNEL);
+       if (!kq)
+               return NULL;
+
+       kq->initialize = initialize;
+       kq->uninitialize = uninitialize;
+       kq->acquire_packet_buffer = acquire_packet_buffer;
+       kq->submit_packet = submit_packet;
+       kq->sync_with_hw = sync_with_hw;
+       kq->rollback_packet = rollback_packet;
+
+       if (kq->initialize(kq, dev, type, KFD_KERNEL_QUEUE_SIZE) == false) {
+               pr_err("kfd: failed to init kernel queue\n");
+               kfree(kq);
+               return NULL;
+       }
+       return kq;
+}
+
+void kernel_queue_uninit(struct kernel_queue *kq)
+{
+       BUG_ON(!kq);
+
+       kq->uninitialize(kq);
+       kfree(kq);
+}
+
+static __attribute__((unused)) void test_kq(struct kfd_dev *dev)
+{
+       struct kernel_queue *kq;
+       uint32_t *buffer, i;
+       int retval;
+
+       BUG_ON(!dev);
+
+       pr_debug("kfd: starting kernel queue test\n");
+
+       kq = kernel_queue_init(dev, KFD_QUEUE_TYPE_HIQ);
+       BUG_ON(!kq);
+
+       retval = kq->acquire_packet_buffer(kq, 5, &buffer);
+       BUG_ON(retval != 0);
+       for (i = 0; i < 5; i++)
+               buffer[i] = kq->nop_packet;
+       kq->submit_packet(kq);
+       kq->sync_with_hw(kq, 1000);
+
+       pr_debug("kfd: ending kernel queue test\n");
+}
+
+
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h
new file mode 100644 (file)
index 0000000..dcd2bdb
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef KFD_KERNEL_QUEUE_H_
+#define KFD_KERNEL_QUEUE_H_
+
+#include <linux/list.h>
+#include <linux/types.h>
+#include "kfd_priv.h"
+
+struct kernel_queue {
+       /* interface */
+       bool    (*initialize)(struct kernel_queue *kq, struct kfd_dev *dev,
+                       enum kfd_queue_type type, unsigned int queue_size);
+       void    (*uninitialize)(struct kernel_queue *kq);
+       int     (*acquire_packet_buffer)(struct kernel_queue *kq,
+                                       size_t packet_size_in_dwords,
+                                       unsigned int **buffer_ptr);
+
+       void    (*submit_packet)(struct kernel_queue *kq);
+       int     (*sync_with_hw)(struct kernel_queue *kq,
+                               unsigned long timeout_ms);
+       void    (*rollback_packet)(struct kernel_queue *kq);
+
+       /* data */
+       struct kfd_dev          *dev;
+       struct mqd_manager      *mqd;
+       struct queue            *queue;
+       uint32_t                pending_wptr;
+       unsigned int            nop_packet;
+
+       struct kfd_mem_obj      *rptr_mem;
+       uint32_t                *rptr_kernel;
+       uint64_t                rptr_gpu_addr;
+       struct kfd_mem_obj      *wptr_mem;
+       uint32_t                *wptr_kernel;
+       uint64_t                wptr_gpu_addr;
+       struct kfd_mem_obj      *pq;
+       uint64_t                pq_gpu_addr;
+       uint32_t                *pq_kernel_addr;
+
+       struct kfd_mem_obj      *fence_mem_obj;
+       uint64_t                fence_gpu_addr;
+       void                    *fence_kernel_address;
+
+       struct list_head        list;
+};
+
+#endif /* KFD_KERNEL_QUEUE_H_ */
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_module.c b/drivers/gpu/drm/amd/amdkfd/kfd_module.c
new file mode 100644 (file)
index 0000000..95d5af1
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include "kfd_priv.h"
+
+#define KFD_DRIVER_AUTHOR      "AMD Inc. and others"
+
+#define KFD_DRIVER_DESC                "Standalone HSA driver for AMD's GPUs"
+#define KFD_DRIVER_DATE                "20141113"
+#define KFD_DRIVER_MAJOR       0
+#define KFD_DRIVER_MINOR       7
+#define KFD_DRIVER_PATCHLEVEL  0
+
+const struct kfd2kgd_calls *kfd2kgd;
+static const struct kgd2kfd_calls kgd2kfd = {
+       .exit           = kgd2kfd_exit,
+       .probe          = kgd2kfd_probe,
+       .device_init    = kgd2kfd_device_init,
+       .device_exit    = kgd2kfd_device_exit,
+       .interrupt      = kgd2kfd_interrupt,
+       .suspend        = kgd2kfd_suspend,
+       .resume         = kgd2kfd_resume,
+};
+
+int sched_policy = KFD_SCHED_POLICY_HWS;
+module_param(sched_policy, int, 0444);
+MODULE_PARM_DESC(sched_policy,
+       "Kernel cmdline parameter that defines the amdkfd scheduling policy");
+
+int max_num_of_processes = KFD_MAX_NUM_OF_PROCESSES_DEFAULT;
+module_param(max_num_of_processes, int, 0444);
+MODULE_PARM_DESC(max_num_of_processes,
+       "Kernel cmdline parameter that defines the amdkfd maximum number of supported processes");
+
+int max_num_of_queues_per_process = KFD_MAX_NUM_OF_QUEUES_PER_PROCESS_DEFAULT;
+module_param(max_num_of_queues_per_process, int, 0444);
+MODULE_PARM_DESC(max_num_of_queues_per_process,
+       "Kernel cmdline parameter that defines the amdkfd maximum number of supported queues per process");
+
+bool kgd2kfd_init(unsigned interface_version,
+                 const struct kfd2kgd_calls *f2g,
+                 const struct kgd2kfd_calls **g2f)
+{
+       /*
+        * Only one interface version is supported,
+        * no kfd/kgd version skew allowed.
+        */
+       if (interface_version != KFD_INTERFACE_VERSION)
+               return false;
+
+       /* Protection against multiple amd kgd loads */
+       if (kfd2kgd)
+               return true;
+
+       kfd2kgd = f2g;
+       *g2f = &kgd2kfd;
+
+       return true;
+}
+EXPORT_SYMBOL(kgd2kfd_init);
+
+void kgd2kfd_exit(void)
+{
+}
+
+static int __init kfd_module_init(void)
+{
+       int err;
+
+       kfd2kgd = NULL;
+
+       /* Verify module parameters */
+       if ((sched_policy < KFD_SCHED_POLICY_HWS) ||
+               (sched_policy > KFD_SCHED_POLICY_NO_HWS)) {
+               pr_err("kfd: sched_policy has invalid value\n");
+               return -1;
+       }
+
+       /* Verify module parameters */
+       if ((max_num_of_processes < 0) ||
+               (max_num_of_processes > KFD_MAX_NUM_OF_PROCESSES)) {
+               pr_err("kfd: max_num_of_processes must be between 0 to KFD_MAX_NUM_OF_PROCESSES\n");
+               return -1;
+       }
+
+       if ((max_num_of_queues_per_process < 0) ||
+               (max_num_of_queues_per_process >
+                       KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)) {
+               pr_err("kfd: max_num_of_queues_per_process must be between 0 to KFD_MAX_NUM_OF_QUEUES_PER_PROCESS\n");
+               return -1;
+       }
+
+       err = kfd_pasid_init();
+       if (err < 0)
+               goto err_pasid;
+
+       err = kfd_chardev_init();
+       if (err < 0)
+               goto err_ioctl;
+
+       err = kfd_topology_init();
+       if (err < 0)
+               goto err_topology;
+
+       kfd_process_create_wq();
+
+       dev_info(kfd_device, "Initialized module\n");
+
+       return 0;
+
+err_topology:
+       kfd_chardev_exit();
+err_ioctl:
+       kfd_pasid_exit();
+err_pasid:
+       return err;
+}
+
+static void __exit kfd_module_exit(void)
+{
+       kfd_process_destroy_wq();
+       kfd_topology_shutdown();
+       kfd_chardev_exit();
+       kfd_pasid_exit();
+       dev_info(kfd_device, "Removed module\n");
+}
+
+module_init(kfd_module_init);
+module_exit(kfd_module_exit);
+
+MODULE_AUTHOR(KFD_DRIVER_AUTHOR);
+MODULE_DESCRIPTION(KFD_DRIVER_DESC);
+MODULE_LICENSE("GPL and additional rights");
+MODULE_VERSION(__stringify(KFD_DRIVER_MAJOR) "."
+              __stringify(KFD_DRIVER_MINOR) "."
+              __stringify(KFD_DRIVER_PATCHLEVEL));
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
new file mode 100644 (file)
index 0000000..adc3147
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include "kfd_priv.h"
+#include "kfd_mqd_manager.h"
+#include "cik_regs.h"
+#include "../../radeon/cik_reg.h"
+
+inline void busy_wait(unsigned long ms)
+{
+       while (time_before(jiffies, ms))
+               cpu_relax();
+}
+
+static inline struct cik_mqd *get_mqd(void *mqd)
+{
+       return (struct cik_mqd *)mqd;
+}
+
+static int init_mqd(struct mqd_manager *mm, void **mqd,
+               struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
+               struct queue_properties *q)
+{
+       uint64_t addr;
+       struct cik_mqd *m;
+       int retval;
+
+       BUG_ON(!mm || !q || !mqd);
+
+       pr_debug("kfd: In func %s\n", __func__);
+
+       retval = kfd2kgd->allocate_mem(mm->dev->kgd,
+                                       sizeof(struct cik_mqd),
+                                       256,
+                                       KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
+                                       (struct kgd_mem **) mqd_mem_obj);
+
+       if (retval != 0)
+               return -ENOMEM;
+
+       m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr;
+       addr = (*mqd_mem_obj)->gpu_addr;
+
+       memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256));
+
+       m->header = 0xC0310800;
+       m->compute_pipelinestat_enable = 1;
+       m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF;
+       m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF;
+       m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF;
+       m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF;
+
+       /*
+        * Make sure to use the last queue state saved on mqd when the cp
+        * reassigns the queue, so when queue is switched on/off (e.g over
+        * subscription or quantum timeout) the context will be consistent
+        */
+       m->cp_hqd_persistent_state =
+                               DEFAULT_CP_HQD_PERSISTENT_STATE | PRELOAD_REQ;
+
+       m->cp_mqd_control             = MQD_CONTROL_PRIV_STATE_EN;
+       m->cp_mqd_base_addr_lo        = lower_32_bits(addr);
+       m->cp_mqd_base_addr_hi        = upper_32_bits(addr);
+
+       m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE | IB_ATC_EN;
+       /* Although WinKFD writes this, I suspect it should not be necessary */
+       m->cp_hqd_ib_control = IB_ATC_EN | DEFAULT_MIN_IB_AVAIL_SIZE;
+
+       m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS |
+                               QUANTUM_DURATION(10);
+
+       /*
+        * Pipe Priority
+        * Identifies the pipe relative priority when this queue is connected
+        * to the pipeline. The pipe priority is against the GFX pipe and HP3D.
+        * In KFD we are using a fixed pipe priority set to CS_MEDIUM.
+        * 0 = CS_LOW (typically below GFX)
+        * 1 = CS_MEDIUM (typically between HP3D and GFX
+        * 2 = CS_HIGH (typically above HP3D)
+        */
+       m->cp_hqd_pipe_priority = 1;
+       m->cp_hqd_queue_priority = 15;
+
+       *mqd = m;
+       if (gart_addr != NULL)
+               *gart_addr = addr;
+       retval = mm->update_mqd(mm, m, q);
+
+       return retval;
+}
+
+static void uninit_mqd(struct mqd_manager *mm, void *mqd,
+                       struct kfd_mem_obj *mqd_mem_obj)
+{
+       BUG_ON(!mm || !mqd);
+       kfd2kgd->free_mem(mm->dev->kgd, (struct kgd_mem *) mqd_mem_obj);
+}
+
+static int load_mqd(struct mqd_manager *mm, void *mqd, uint32_t pipe_id,
+                       uint32_t queue_id, uint32_t __user *wptr)
+{
+       return kfd2kgd->hqd_load(mm->dev->kgd, mqd, pipe_id, queue_id, wptr);
+
+}
+
+static int update_mqd(struct mqd_manager *mm, void *mqd,
+                       struct queue_properties *q)
+{
+       struct cik_mqd *m;
+
+       BUG_ON(!mm || !q || !mqd);
+
+       pr_debug("kfd: In func %s\n", __func__);
+
+       m = get_mqd(mqd);
+       m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE |
+                               DEFAULT_MIN_AVAIL_SIZE | PQ_ATC_EN;
+
+       /*
+        * Calculating queue size which is log base 2 of actual queue size -1
+        * dwords and another -1 for ffs
+        */
+       m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int))
+                                                               - 1 - 1;
+       m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
+       m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8);
+       m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
+       m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
+       m->cp_hqd_pq_doorbell_control = DOORBELL_EN |
+                                       DOORBELL_OFFSET(q->doorbell_off);
+
+       m->cp_hqd_vmid = q->vmid;
+
+       if (q->format == KFD_QUEUE_FORMAT_AQL) {
+               m->cp_hqd_iq_rptr = AQL_ENABLE;
+               m->cp_hqd_pq_control |= NO_UPDATE_RPTR;
+       }
+
+       m->cp_hqd_active = 0;
+       q->is_active = false;
+       if (q->queue_size > 0 &&
+                       q->queue_address != 0 &&
+                       q->queue_percent > 0) {
+               m->cp_hqd_active = 1;
+               q->is_active = true;
+       }
+
+       return 0;
+}
+
+static int destroy_mqd(struct mqd_manager *mm, void *mqd,
+                       enum kfd_preempt_type type,
+                       unsigned int timeout, uint32_t pipe_id,
+                       uint32_t queue_id)
+{
+       return kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout,
+                                       pipe_id, queue_id);
+}
+
+static bool is_occupied(struct mqd_manager *mm, void *mqd,
+                       uint64_t queue_address, uint32_t pipe_id,
+                       uint32_t queue_id)
+{
+
+       return kfd2kgd->hqd_is_occupies(mm->dev->kgd, queue_address,
+                                       pipe_id, queue_id);
+
+}
+
+/*
+ * HIQ MQD Implementation, concrete implementation for HIQ MQD implementation.
+ * The HIQ queue in Kaveri is using the same MQD structure as all the user mode
+ * queues but with different initial values.
+ */
+
+static int init_mqd_hiq(struct mqd_manager *mm, void **mqd,
+               struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
+               struct queue_properties *q)
+{
+       uint64_t addr;
+       struct cik_mqd *m;
+       int retval;
+
+       BUG_ON(!mm || !q || !mqd || !mqd_mem_obj);
+
+       pr_debug("kfd: In func %s\n", __func__);
+
+       retval = kfd2kgd->allocate_mem(mm->dev->kgd,
+                                       sizeof(struct cik_mqd),
+                                       256,
+                                       KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
+                                       (struct kgd_mem **) mqd_mem_obj);
+
+       if (retval != 0)
+               return -ENOMEM;
+
+       m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr;
+       addr = (*mqd_mem_obj)->gpu_addr;
+
+       memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256));
+
+       m->header = 0xC0310800;
+       m->compute_pipelinestat_enable = 1;
+       m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF;
+       m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF;
+       m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF;
+       m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF;
+
+       m->cp_hqd_persistent_state = DEFAULT_CP_HQD_PERSISTENT_STATE |
+                                       PRELOAD_REQ;
+       m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS |
+                               QUANTUM_DURATION(10);
+
+       m->cp_mqd_control             = MQD_CONTROL_PRIV_STATE_EN;
+       m->cp_mqd_base_addr_lo        = lower_32_bits(addr);
+       m->cp_mqd_base_addr_hi        = upper_32_bits(addr);
+
+       m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE;
+
+       /*
+        * Pipe Priority
+        * Identifies the pipe relative priority when this queue is connected
+        * to the pipeline. The pipe priority is against the GFX pipe and HP3D.
+        * In KFD we are using a fixed pipe priority set to CS_MEDIUM.
+        * 0 = CS_LOW (typically below GFX)
+        * 1 = CS_MEDIUM (typically between HP3D and GFX
+        * 2 = CS_HIGH (typically above HP3D)
+        */
+       m->cp_hqd_pipe_priority = 1;
+       m->cp_hqd_queue_priority = 15;
+
+       *mqd = m;
+       if (gart_addr)
+               *gart_addr = addr;
+       retval = mm->update_mqd(mm, m, q);
+
+       return retval;
+}
+
+static int update_mqd_hiq(struct mqd_manager *mm, void *mqd,
+                               struct queue_properties *q)
+{
+       struct cik_mqd *m;
+
+       BUG_ON(!mm || !q || !mqd);
+
+       pr_debug("kfd: In func %s\n", __func__);
+
+       m = get_mqd(mqd);
+       m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE |
+                               DEFAULT_MIN_AVAIL_SIZE |
+                               PRIV_STATE |
+                               KMD_QUEUE;
+
+       /*
+        * Calculating queue size which is log base 2 of actual queue
+        * size -1 dwords
+        */
+       m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int))
+                                                               - 1 - 1;
+       m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
+       m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8);
+       m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
+       m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
+       m->cp_hqd_pq_doorbell_control = DOORBELL_EN |
+                                       DOORBELL_OFFSET(q->doorbell_off);
+
+       m->cp_hqd_vmid = q->vmid;
+
+       m->cp_hqd_active = 0;
+       q->is_active = false;
+       if (q->queue_size > 0 &&
+                       q->queue_address != 0 &&
+                       q->queue_percent > 0) {
+               m->cp_hqd_active = 1;
+               q->is_active = true;
+       }
+
+       return 0;
+}
+
+struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type,
+                                       struct kfd_dev *dev)
+{
+       struct mqd_manager *mqd;
+
+       BUG_ON(!dev);
+       BUG_ON(type >= KFD_MQD_TYPE_MAX);
+
+       pr_debug("kfd: In func %s\n", __func__);
+
+       mqd = kzalloc(sizeof(struct mqd_manager), GFP_KERNEL);
+       if (!mqd)
+               return NULL;
+
+       mqd->dev = dev;
+
+       switch (type) {
+       case KFD_MQD_TYPE_CIK_CP:
+       case KFD_MQD_TYPE_CIK_COMPUTE:
+               mqd->init_mqd = init_mqd;
+               mqd->uninit_mqd = uninit_mqd;
+               mqd->load_mqd = load_mqd;
+               mqd->update_mqd = update_mqd;
+               mqd->destroy_mqd = destroy_mqd;
+               mqd->is_occupied = is_occupied;
+               break;
+       case KFD_MQD_TYPE_CIK_HIQ:
+               mqd->init_mqd = init_mqd_hiq;
+               mqd->uninit_mqd = uninit_mqd;
+               mqd->load_mqd = load_mqd;
+               mqd->update_mqd = update_mqd_hiq;
+               mqd->destroy_mqd = destroy_mqd;
+               mqd->is_occupied = is_occupied;
+               break;
+       default:
+               kfree(mqd);
+               return NULL;
+       }
+
+       return mqd;
+}
+
+/* SDMA queues should be implemented here when the cp will supports them */
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h
new file mode 100644 (file)
index 0000000..213a71e
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef KFD_MQD_MANAGER_H_
+#define KFD_MQD_MANAGER_H_
+
+#include "kfd_priv.h"
+
+/**
+ * struct mqd_manager
+ *
+ * @init_mqd: Allocates the mqd buffer on local gpu memory and initialize it.
+ *
+ * @load_mqd: Loads the mqd to a concrete hqd slot. Used only for no cp
+ * scheduling mode.
+ *
+ * @update_mqd: Handles a update call for the MQD
+ *
+ * @destroy_mqd: Destroys the HQD slot and by that preempt the relevant queue.
+ * Used only for no cp scheduling.
+ *
+ * @uninit_mqd: Releases the mqd buffer from local gpu memory.
+ *
+ * @is_occupied: Checks if the relevant HQD slot is occupied.
+ *
+ * @mqd_mutex: Mqd manager mutex.
+ *
+ * @dev: The kfd device structure coupled with this module.
+ *
+ * MQD stands for Memory Queue Descriptor which represents the current queue
+ * state in the memory and initiate the HQD (Hardware Queue Descriptor) state.
+ * This structure is actually a base class for the different types of MQDs
+ * structures for the variant ASICs that should be supported in the future.
+ * This base class is also contains all the MQD specific operations.
+ * Another important thing to mention is that each queue has a MQD that keeps
+ * his state (or context) after each preemption or reassignment.
+ * Basically there are a instances of the mqd manager class per MQD type per
+ * ASIC. Currently the kfd driver supports only Kaveri so there are instances
+ * per KFD_MQD_TYPE for each device.
+ *
+ */
+
+struct mqd_manager {
+       int     (*init_mqd)(struct mqd_manager *mm, void **mqd,
+                       struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
+                       struct queue_properties *q);
+
+       int     (*load_mqd)(struct mqd_manager *mm, void *mqd,
+                               uint32_t pipe_id, uint32_t queue_id,
+                               uint32_t __user *wptr);
+
+       int     (*update_mqd)(struct mqd_manager *mm, void *mqd,
+                               struct queue_properties *q);
+
+       int     (*destroy_mqd)(struct mqd_manager *mm, void *mqd,
+                               enum kfd_preempt_type type,
+                               unsigned int timeout, uint32_t pipe_id,
+                               uint32_t queue_id);
+
+       void    (*uninit_mqd)(struct mqd_manager *mm, void *mqd,
+                               struct kfd_mem_obj *mqd_mem_obj);
+
+       bool    (*is_occupied)(struct mqd_manager *mm, void *mqd,
+                               uint64_t queue_address, uint32_t pipe_id,
+                               uint32_t queue_id);
+
+       struct mutex    mqd_mutex;
+       struct kfd_dev  *dev;
+};
+
+#endif /* KFD_MQD_MANAGER_H_ */
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c
new file mode 100644 (file)
index 0000000..5ce9233
--- /dev/null
@@ -0,0 +1,565 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include "kfd_device_queue_manager.h"
+#include "kfd_kernel_queue.h"
+#include "kfd_priv.h"
+#include "kfd_pm4_headers.h"
+#include "kfd_pm4_opcodes.h"
+
+static inline void inc_wptr(unsigned int *wptr, unsigned int increment_bytes,
+                               unsigned int buffer_size_bytes)
+{
+       unsigned int temp = *wptr + increment_bytes / sizeof(uint32_t);
+
+       BUG_ON((temp * sizeof(uint32_t)) > buffer_size_bytes);
+       *wptr = temp;
+}
+
+static unsigned int build_pm4_header(unsigned int opcode, size_t packet_size)
+{
+       union PM4_MES_TYPE_3_HEADER header;
+
+       header.u32all = 0;
+       header.opcode = opcode;
+       header.count = packet_size/sizeof(uint32_t) - 2;
+       header.type = PM4_TYPE_3;
+
+       return header.u32all;
+}
+
+static void pm_calc_rlib_size(struct packet_manager *pm,
+                               unsigned int *rlib_size,
+                               bool *over_subscription)
+{
+       unsigned int process_count, queue_count;
+
+       BUG_ON(!pm || !rlib_size || !over_subscription);
+
+       process_count = pm->dqm->processes_count;
+       queue_count = pm->dqm->queue_count;
+
+       /* check if there is over subscription*/
+       *over_subscription = false;
+       if ((process_count > 1) ||
+               queue_count > PIPE_PER_ME_CP_SCHEDULING * QUEUES_PER_PIPE) {
+               *over_subscription = true;
+               pr_debug("kfd: over subscribed runlist\n");
+       }
+
+       /* calculate run list ib allocation size */
+       *rlib_size = process_count * sizeof(struct pm4_map_process) +
+                    queue_count * sizeof(struct pm4_map_queues);
+
+       /*
+        * Increase the allocation size in case we need a chained run list
+        * when over subscription
+        */
+       if (*over_subscription)
+               *rlib_size += sizeof(struct pm4_runlist);
+
+       pr_debug("kfd: runlist ib size %d\n", *rlib_size);
+}
+
+static int pm_allocate_runlist_ib(struct packet_manager *pm,
+                               unsigned int **rl_buffer,
+                               uint64_t *rl_gpu_buffer,
+                               unsigned int *rl_buffer_size,
+                               bool *is_over_subscription)
+{
+       int retval;
+
+       BUG_ON(!pm);
+       BUG_ON(pm->allocated == true);
+       BUG_ON(is_over_subscription == NULL);
+
+       pm_calc_rlib_size(pm, rl_buffer_size, is_over_subscription);
+
+       retval = kfd2kgd->allocate_mem(pm->dqm->dev->kgd,
+                                       *rl_buffer_size,
+                                       PAGE_SIZE,
+                                       KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
+                                       (struct kgd_mem **) &pm->ib_buffer_obj);
+
+       if (retval != 0) {
+               pr_err("kfd: failed to allocate runlist IB\n");
+               return retval;
+       }
+
+       *(void **)rl_buffer = pm->ib_buffer_obj->cpu_ptr;
+       *rl_gpu_buffer = pm->ib_buffer_obj->gpu_addr;
+
+       memset(*rl_buffer, 0, *rl_buffer_size);
+       pm->allocated = true;
+       return retval;
+}
+
+static int pm_create_runlist(struct packet_manager *pm, uint32_t *buffer,
+                       uint64_t ib, size_t ib_size_in_dwords, bool chain)
+{
+       struct pm4_runlist *packet;
+
+       BUG_ON(!pm || !buffer || !ib);
+
+       packet = (struct pm4_runlist *)buffer;
+
+       memset(buffer, 0, sizeof(struct pm4_runlist));
+       packet->header.u32all = build_pm4_header(IT_RUN_LIST,
+                                               sizeof(struct pm4_runlist));
+
+       packet->bitfields4.ib_size = ib_size_in_dwords;
+       packet->bitfields4.chain = chain ? 1 : 0;
+       packet->bitfields4.offload_polling = 0;
+       packet->bitfields4.valid = 1;
+       packet->ordinal2 = lower_32_bits(ib);
+       packet->bitfields3.ib_base_hi = upper_32_bits(ib);
+
+       return 0;
+}
+
+static int pm_create_map_process(struct packet_manager *pm, uint32_t *buffer,
+                               struct qcm_process_device *qpd)
+{
+       struct pm4_map_process *packet;
+       struct queue *cur;
+       uint32_t num_queues;
+
+       BUG_ON(!pm || !buffer || !qpd);
+
+       packet = (struct pm4_map_process *)buffer;
+
+       pr_debug("kfd: In func %s\n", __func__);
+
+       memset(buffer, 0, sizeof(struct pm4_map_process));
+
+       packet->header.u32all = build_pm4_header(IT_MAP_PROCESS,
+                                       sizeof(struct pm4_map_process));
+       packet->bitfields2.diq_enable = (qpd->is_debug) ? 1 : 0;
+       packet->bitfields2.process_quantum = 1;
+       packet->bitfields2.pasid = qpd->pqm->process->pasid;
+       packet->bitfields3.page_table_base = qpd->page_table_base;
+       packet->bitfields10.gds_size = qpd->gds_size;
+       packet->bitfields10.num_gws = qpd->num_gws;
+       packet->bitfields10.num_oac = qpd->num_oac;
+       num_queues = 0;
+       list_for_each_entry(cur, &qpd->queues_list, list)
+               num_queues++;
+       packet->bitfields10.num_queues = num_queues;
+
+       packet->sh_mem_config = qpd->sh_mem_config;
+       packet->sh_mem_bases = qpd->sh_mem_bases;
+       packet->sh_mem_ape1_base = qpd->sh_mem_ape1_base;
+       packet->sh_mem_ape1_limit = qpd->sh_mem_ape1_limit;
+
+       packet->gds_addr_lo = lower_32_bits(qpd->gds_context_area);
+       packet->gds_addr_hi = upper_32_bits(qpd->gds_context_area);
+
+       return 0;
+}
+
+static int pm_create_map_queue(struct packet_manager *pm, uint32_t *buffer,
+                               struct queue *q)
+{
+       struct pm4_map_queues *packet;
+
+       BUG_ON(!pm || !buffer || !q);
+
+       pr_debug("kfd: In func %s\n", __func__);
+
+       packet = (struct pm4_map_queues *)buffer;
+       memset(buffer, 0, sizeof(struct pm4_map_queues));
+
+       packet->header.u32all = build_pm4_header(IT_MAP_QUEUES,
+                                               sizeof(struct pm4_map_queues));
+       packet->bitfields2.alloc_format =
+                               alloc_format__mes_map_queues__one_per_pipe;
+       packet->bitfields2.num_queues = 1;
+       packet->bitfields2.queue_sel =
+               queue_sel__mes_map_queues__map_to_hws_determined_queue_slots;
+
+       packet->bitfields2.vidmem = (q->properties.is_interop) ?
+                       vidmem__mes_map_queues__uses_video_memory :
+                       vidmem__mes_map_queues__uses_no_video_memory;
+
+       switch (q->properties.type) {
+       case KFD_QUEUE_TYPE_COMPUTE:
+       case KFD_QUEUE_TYPE_DIQ:
+               packet->bitfields2.engine_sel =
+                               engine_sel__mes_map_queues__compute;
+               break;
+       case KFD_QUEUE_TYPE_SDMA:
+               packet->bitfields2.engine_sel =
+                               engine_sel__mes_map_queues__sdma0;
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       packet->mes_map_queues_ordinals[0].bitfields3.doorbell_offset =
+                       q->properties.doorbell_off;
+
+       packet->mes_map_queues_ordinals[0].mqd_addr_lo =
+                       lower_32_bits(q->gart_mqd_addr);
+
+       packet->mes_map_queues_ordinals[0].mqd_addr_hi =
+                       upper_32_bits(q->gart_mqd_addr);
+
+       packet->mes_map_queues_ordinals[0].wptr_addr_lo =
+                       lower_32_bits((uint64_t)q->properties.write_ptr);
+
+       packet->mes_map_queues_ordinals[0].wptr_addr_hi =
+                       upper_32_bits((uint64_t)q->properties.write_ptr);
+
+       return 0;
+}
+
+static int pm_create_runlist_ib(struct packet_manager *pm,
+                               struct list_head *queues,
+                               uint64_t *rl_gpu_addr,
+                               size_t *rl_size_bytes)
+{
+       unsigned int alloc_size_bytes;
+       unsigned int *rl_buffer, rl_wptr, i;
+       int retval, proccesses_mapped;
+       struct device_process_node *cur;
+       struct qcm_process_device *qpd;
+       struct queue *q;
+       struct kernel_queue *kq;
+       bool is_over_subscription;
+
+       BUG_ON(!pm || !queues || !rl_size_bytes || !rl_gpu_addr);
+
+       rl_wptr = retval = proccesses_mapped = 0;
+
+       retval = pm_allocate_runlist_ib(pm, &rl_buffer, rl_gpu_addr,
+                               &alloc_size_bytes, &is_over_subscription);
+       if (retval != 0)
+               return retval;
+
+       *rl_size_bytes = alloc_size_bytes;
+
+       pr_debug("kfd: In func %s\n", __func__);
+       pr_debug("kfd: building runlist ib process count: %d queues count %d\n",
+               pm->dqm->processes_count, pm->dqm->queue_count);
+
+       /* build the run list ib packet */
+       list_for_each_entry(cur, queues, list) {
+               qpd = cur->qpd;
+               /* build map process packet */
+               if (proccesses_mapped >= pm->dqm->processes_count) {
+                       pr_debug("kfd: not enough space left in runlist IB\n");
+                       pm_release_ib(pm);
+                       return -ENOMEM;
+               }
+               retval = pm_create_map_process(pm, &rl_buffer[rl_wptr], qpd);
+               if (retval != 0)
+                       return retval;
+               proccesses_mapped++;
+               inc_wptr(&rl_wptr, sizeof(struct pm4_map_process),
+                               alloc_size_bytes);
+
+               list_for_each_entry(kq, &qpd->priv_queue_list, list) {
+                       if (kq->queue->properties.is_active != true)
+                               continue;
+                       retval = pm_create_map_queue(pm, &rl_buffer[rl_wptr],
+                                                       kq->queue);
+                       if (retval != 0)
+                               return retval;
+                       inc_wptr(&rl_wptr, sizeof(struct pm4_map_queues),
+                                       alloc_size_bytes);
+               }
+
+               list_for_each_entry(q, &qpd->queues_list, list) {
+                       if (q->properties.is_active != true)
+                               continue;
+                       retval = pm_create_map_queue(pm,
+                                               &rl_buffer[rl_wptr], q);
+                       if (retval != 0)
+                               return retval;
+                       inc_wptr(&rl_wptr, sizeof(struct pm4_map_queues),
+                                       alloc_size_bytes);
+               }
+       }
+
+       pr_debug("kfd: finished map process and queues to runlist\n");
+
+       if (is_over_subscription)
+               pm_create_runlist(pm, &rl_buffer[rl_wptr], *rl_gpu_addr,
+                               alloc_size_bytes / sizeof(uint32_t), true);
+
+       for (i = 0; i < alloc_size_bytes / sizeof(uint32_t); i++)
+               pr_debug("0x%2X ", rl_buffer[i]);
+       pr_debug("\n");
+
+       return 0;
+}
+
+int pm_init(struct packet_manager *pm, struct device_queue_manager *dqm)
+{
+       BUG_ON(!dqm);
+
+       pm->dqm = dqm;
+       mutex_init(&pm->lock);
+       pm->priv_queue = kernel_queue_init(dqm->dev, KFD_QUEUE_TYPE_HIQ);
+       if (pm->priv_queue == NULL) {
+               mutex_destroy(&pm->lock);
+               return -ENOMEM;
+       }
+       pm->allocated = false;
+
+       return 0;
+}
+
+void pm_uninit(struct packet_manager *pm)
+{
+       BUG_ON(!pm);
+
+       mutex_destroy(&pm->lock);
+       kernel_queue_uninit(pm->priv_queue);
+}
+
+int pm_send_set_resources(struct packet_manager *pm,
+                               struct scheduling_resources *res)
+{
+       struct pm4_set_resources *packet;
+
+       BUG_ON(!pm || !res);
+
+       pr_debug("kfd: In func %s\n", __func__);
+
+       mutex_lock(&pm->lock);
+       pm->priv_queue->acquire_packet_buffer(pm->priv_queue,
+                                       sizeof(*packet) / sizeof(uint32_t),
+                       (unsigned int **)&packet);
+       if (packet == NULL) {
+               mutex_unlock(&pm->lock);
+               pr_err("kfd: failed to allocate buffer on kernel queue\n");
+               return -ENOMEM;
+       }
+
+       memset(packet, 0, sizeof(struct pm4_set_resources));
+       packet->header.u32all = build_pm4_header(IT_SET_RESOURCES,
+                                       sizeof(struct pm4_set_resources));
+
+       packet->bitfields2.queue_type =
+                       queue_type__mes_set_resources__hsa_interface_queue_hiq;
+       packet->bitfields2.vmid_mask = res->vmid_mask;
+       packet->bitfields2.unmap_latency = KFD_UNMAP_LATENCY;
+       packet->bitfields7.oac_mask = res->oac_mask;
+       packet->bitfields8.gds_heap_base = res->gds_heap_base;
+       packet->bitfields8.gds_heap_size = res->gds_heap_size;
+
+       packet->gws_mask_lo = lower_32_bits(res->gws_mask);
+       packet->gws_mask_hi = upper_32_bits(res->gws_mask);
+
+       packet->queue_mask_lo = lower_32_bits(res->queue_mask);
+       packet->queue_mask_hi = upper_32_bits(res->queue_mask);
+
+       pm->priv_queue->submit_packet(pm->priv_queue);
+       pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT);
+
+       mutex_unlock(&pm->lock);
+
+       return 0;
+}
+
+int pm_send_runlist(struct packet_manager *pm, struct list_head *dqm_queues)
+{
+       uint64_t rl_gpu_ib_addr;
+       uint32_t *rl_buffer;
+       size_t rl_ib_size, packet_size_dwords;
+       int retval;
+
+       BUG_ON(!pm || !dqm_queues);
+
+       retval = pm_create_runlist_ib(pm, dqm_queues, &rl_gpu_ib_addr,
+                                       &rl_ib_size);
+       if (retval != 0)
+               goto fail_create_runlist_ib;
+
+       pr_debug("kfd: runlist IB address: 0x%llX\n", rl_gpu_ib_addr);
+
+       packet_size_dwords = sizeof(struct pm4_runlist) / sizeof(uint32_t);
+       mutex_lock(&pm->lock);
+
+       retval = pm->priv_queue->acquire_packet_buffer(pm->priv_queue,
+                                       packet_size_dwords, &rl_buffer);
+       if (retval != 0)
+               goto fail_acquire_packet_buffer;
+
+       retval = pm_create_runlist(pm, rl_buffer, rl_gpu_ib_addr,
+                                       rl_ib_size / sizeof(uint32_t), false);
+       if (retval != 0)
+               goto fail_create_runlist;
+
+       pm->priv_queue->submit_packet(pm->priv_queue);
+       pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT);
+
+       mutex_unlock(&pm->lock);
+
+       return retval;
+
+fail_create_runlist:
+       pm->priv_queue->rollback_packet(pm->priv_queue);
+fail_acquire_packet_buffer:
+       mutex_unlock(&pm->lock);
+fail_create_runlist_ib:
+       if (pm->allocated == true)
+               pm_release_ib(pm);
+       return retval;
+}
+
+int pm_send_query_status(struct packet_manager *pm, uint64_t fence_address,
+                       uint32_t fence_value)
+{
+       int retval;
+       struct pm4_query_status *packet;
+
+       BUG_ON(!pm || !fence_address);
+
+       mutex_lock(&pm->lock);
+       retval = pm->priv_queue->acquire_packet_buffer(
+                       pm->priv_queue,
+                       sizeof(struct pm4_query_status) / sizeof(uint32_t),
+                       (unsigned int **)&packet);
+       if (retval != 0)
+               goto fail_acquire_packet_buffer;
+
+       packet->header.u32all = build_pm4_header(IT_QUERY_STATUS,
+                                       sizeof(struct pm4_query_status));
+
+       packet->bitfields2.context_id = 0;
+       packet->bitfields2.interrupt_sel =
+                       interrupt_sel__mes_query_status__completion_status;
+       packet->bitfields2.command =
+                       command__mes_query_status__fence_only_after_write_ack;
+
+       packet->addr_hi = upper_32_bits((uint64_t)fence_address);
+       packet->addr_lo = lower_32_bits((uint64_t)fence_address);
+       packet->data_hi = upper_32_bits((uint64_t)fence_value);
+       packet->data_lo = lower_32_bits((uint64_t)fence_value);
+
+       pm->priv_queue->submit_packet(pm->priv_queue);
+       pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT);
+       mutex_unlock(&pm->lock);
+
+       return 0;
+
+fail_acquire_packet_buffer:
+       mutex_unlock(&pm->lock);
+       return retval;
+}
+
+int pm_send_unmap_queue(struct packet_manager *pm, enum kfd_queue_type type,
+                       enum kfd_preempt_type_filter mode,
+                       uint32_t filter_param, bool reset,
+                       unsigned int sdma_engine)
+{
+       int retval;
+       uint32_t *buffer;
+       struct pm4_unmap_queues *packet;
+
+       BUG_ON(!pm);
+
+       mutex_lock(&pm->lock);
+       retval = pm->priv_queue->acquire_packet_buffer(
+                       pm->priv_queue,
+                       sizeof(struct pm4_unmap_queues) / sizeof(uint32_t),
+                       &buffer);
+       if (retval != 0)
+               goto err_acquire_packet_buffer;
+
+       packet = (struct pm4_unmap_queues *)buffer;
+       memset(buffer, 0, sizeof(struct pm4_unmap_queues));
+
+       packet->header.u32all = build_pm4_header(IT_UNMAP_QUEUES,
+                                       sizeof(struct pm4_unmap_queues));
+       switch (type) {
+       case KFD_QUEUE_TYPE_COMPUTE:
+       case KFD_QUEUE_TYPE_DIQ:
+               packet->bitfields2.engine_sel =
+                       engine_sel__mes_unmap_queues__compute;
+               break;
+       case KFD_QUEUE_TYPE_SDMA:
+               packet->bitfields2.engine_sel =
+                       engine_sel__mes_unmap_queues__sdma0 + sdma_engine;
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       if (reset)
+               packet->bitfields2.action =
+                               action__mes_unmap_queues__reset_queues;
+       else
+               packet->bitfields2.action =
+                               action__mes_unmap_queues__preempt_queues;
+
+       switch (mode) {
+       case KFD_PREEMPT_TYPE_FILTER_SINGLE_QUEUE:
+               packet->bitfields2.queue_sel =
+                               queue_sel__mes_unmap_queues__perform_request_on_specified_queues;
+               packet->bitfields2.num_queues = 1;
+               packet->bitfields3b.doorbell_offset0 = filter_param;
+               break;
+       case KFD_PREEMPT_TYPE_FILTER_BY_PASID:
+               packet->bitfields2.queue_sel =
+                               queue_sel__mes_unmap_queues__perform_request_on_pasid_queues;
+               packet->bitfields3a.pasid = filter_param;
+               break;
+       case KFD_PREEMPT_TYPE_FILTER_ALL_QUEUES:
+               packet->bitfields2.queue_sel =
+                               queue_sel__mes_unmap_queues__perform_request_on_all_active_queues;
+               break;
+       default:
+               BUG();
+               break;
+       };
+
+       pm->priv_queue->submit_packet(pm->priv_queue);
+       pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT);
+
+       mutex_unlock(&pm->lock);
+       return 0;
+
+err_acquire_packet_buffer:
+       mutex_unlock(&pm->lock);
+       return retval;
+}
+
+void pm_release_ib(struct packet_manager *pm)
+{
+       BUG_ON(!pm);
+
+       mutex_lock(&pm->lock);
+       if (pm->allocated) {
+               kfd2kgd->free_mem(pm->dqm->dev->kgd,
+                               (struct kgd_mem *) pm->ib_buffer_obj);
+               pm->allocated = false;
+       }
+       mutex_unlock(&pm->lock);
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_pasid.c b/drivers/gpu/drm/amd/amdkfd/kfd_pasid.c
new file mode 100644 (file)
index 0000000..2458ab7
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/slab.h>
+#include <linux/types.h>
+#include "kfd_priv.h"
+
+static unsigned long *pasid_bitmap;
+static unsigned int pasid_limit;
+static DEFINE_MUTEX(pasid_mutex);
+
+int kfd_pasid_init(void)
+{
+       pasid_limit = max_num_of_processes;
+
+       pasid_bitmap = kzalloc(DIV_ROUND_UP(pasid_limit, BITS_PER_BYTE),
+                               GFP_KERNEL);
+       if (!pasid_bitmap)
+               return -ENOMEM;
+
+       set_bit(0, pasid_bitmap); /* PASID 0 is reserved. */
+
+       return 0;
+}
+
+void kfd_pasid_exit(void)
+{
+       kfree(pasid_bitmap);
+}
+
+bool kfd_set_pasid_limit(unsigned int new_limit)
+{
+       if (new_limit < pasid_limit) {
+               bool ok;
+
+               mutex_lock(&pasid_mutex);
+
+               /* ensure that no pasids >= new_limit are in-use */
+               ok = (find_next_bit(pasid_bitmap, pasid_limit, new_limit) ==
+                                                               pasid_limit);
+               if (ok)
+                       pasid_limit = new_limit;
+
+               mutex_unlock(&pasid_mutex);
+
+               return ok;
+       }
+
+       return true;
+}
+
+inline unsigned int kfd_get_pasid_limit(void)
+{
+       return pasid_limit;
+}
+
+unsigned int kfd_pasid_alloc(void)
+{
+       unsigned int found;
+
+       mutex_lock(&pasid_mutex);
+
+       found = find_first_zero_bit(pasid_bitmap, pasid_limit);
+       if (found == pasid_limit)
+               found = 0;
+       else
+               set_bit(found, pasid_bitmap);
+
+       mutex_unlock(&pasid_mutex);
+
+       return found;
+}
+
+void kfd_pasid_free(unsigned int pasid)
+{
+       BUG_ON(pasid == 0 || pasid >= pasid_limit);
+       clear_bit(pasid, pasid_bitmap);
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers.h b/drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers.h
new file mode 100644 (file)
index 0000000..071ad57
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef KFD_PM4_HEADERS_H_
+#define KFD_PM4_HEADERS_H_
+
+#ifndef PM4_MES_HEADER_DEFINED
+#define PM4_MES_HEADER_DEFINED
+union PM4_MES_TYPE_3_HEADER {
+       struct {
+               uint32_t reserved1:8;   /* < reserved */
+               uint32_t opcode:8;      /* < IT opcode */
+               uint32_t count:14;      /* < number of DWORDs - 1
+                                        * in the information body.
+                                        */
+               uint32_t type:2;        /* < packet identifier.
+                                        * It should be 3 for type 3 packets
+                                        */
+       };
+       uint32_t u32all;
+};
+#endif /* PM4_MES_HEADER_DEFINED */
+
+/* --------------------MES_SET_RESOURCES-------------------- */
+
+#ifndef PM4_MES_SET_RESOURCES_DEFINED
+#define PM4_MES_SET_RESOURCES_DEFINED
+enum set_resources_queue_type_enum {
+       queue_type__mes_set_resources__kernel_interface_queue_kiq = 0,
+       queue_type__mes_set_resources__hsa_interface_queue_hiq = 1,
+       queue_type__mes_set_resources__hsa_debug_interface_queue = 4
+};
+
+struct pm4_set_resources {
+       union {
+               union PM4_MES_TYPE_3_HEADER header;     /* header */
+               uint32_t ordinal1;
+       };
+
+       union {
+               struct {
+                       uint32_t vmid_mask:16;
+                       uint32_t unmap_latency:8;
+                       uint32_t reserved1:5;
+                       enum set_resources_queue_type_enum queue_type:3;
+               } bitfields2;
+               uint32_t ordinal2;
+       };
+
+       uint32_t queue_mask_lo;
+       uint32_t queue_mask_hi;
+       uint32_t gws_mask_lo;
+       uint32_t gws_mask_hi;
+
+       union {
+               struct {
+                       uint32_t oac_mask:16;
+                       uint32_t reserved2:16;
+               } bitfields7;
+               uint32_t ordinal7;
+       };
+
+       union {
+               struct {
+                       uint32_t gds_heap_base:6;
+                       uint32_t reserved3:5;
+                       uint32_t gds_heap_size:6;
+                       uint32_t reserved4:15;
+               } bitfields8;
+               uint32_t ordinal8;
+       };
+
+};
+#endif
+
+/*--------------------MES_RUN_LIST-------------------- */
+
+#ifndef PM4_MES_RUN_LIST_DEFINED
+#define PM4_MES_RUN_LIST_DEFINED
+
+struct pm4_runlist {
+       union {
+               union PM4_MES_TYPE_3_HEADER header;     /* header */
+               uint32_t ordinal1;
+       };
+
+       union {
+               struct {
+                       uint32_t reserved1:2;
+                       uint32_t ib_base_lo:30;
+               } bitfields2;
+               uint32_t ordinal2;
+       };
+
+       union {
+               struct {
+                       uint32_t ib_base_hi:16;
+                       uint32_t reserved2:16;
+               } bitfields3;
+               uint32_t ordinal3;
+       };
+
+       union {
+               struct {
+                       uint32_t ib_size:20;
+                       uint32_t chain:1;
+                       uint32_t offload_polling:1;
+                       uint32_t reserved3:1;
+                       uint32_t valid:1;
+                       uint32_t reserved4:8;
+               } bitfields4;
+               uint32_t ordinal4;
+       };
+
+};
+#endif
+
+/*--------------------MES_MAP_PROCESS-------------------- */
+
+#ifndef PM4_MES_MAP_PROCESS_DEFINED
+#define PM4_MES_MAP_PROCESS_DEFINED
+
+struct pm4_map_process {
+       union {
+               union PM4_MES_TYPE_3_HEADER header;     /* header */
+               uint32_t ordinal1;
+       };
+
+       union {
+               struct {
+                       uint32_t pasid:16;
+                       uint32_t reserved1:8;
+                       uint32_t diq_enable:1;
+                       uint32_t process_quantum:7;
+               } bitfields2;
+               uint32_t ordinal2;
+       };
+
+       union {
+               struct {
+                       uint32_t page_table_base:28;
+                       uint32_t reserved3:4;
+               } bitfields3;
+               uint32_t ordinal3;
+       };
+
+       uint32_t sh_mem_bases;
+       uint32_t sh_mem_ape1_base;
+       uint32_t sh_mem_ape1_limit;
+       uint32_t sh_mem_config;
+       uint32_t gds_addr_lo;
+       uint32_t gds_addr_hi;
+
+       union {
+               struct {
+                       uint32_t num_gws:6;
+                       uint32_t reserved4:2;
+                       uint32_t num_oac:4;
+                       uint32_t reserved5:4;
+                       uint32_t gds_size:6;
+                       uint32_t num_queues:10;
+               } bitfields10;
+               uint32_t ordinal10;
+       };
+
+};
+#endif
+
+/*--------------------MES_MAP_QUEUES--------------------*/
+
+#ifndef PM4_MES_MAP_QUEUES_DEFINED
+#define PM4_MES_MAP_QUEUES_DEFINED
+enum map_queues_queue_sel_enum {
+       queue_sel__mes_map_queues__map_to_specified_queue_slots = 0,
+       queue_sel__mes_map_queues__map_to_hws_determined_queue_slots = 1,
+       queue_sel__mes_map_queues__enable_process_queues = 2
+};
+
+enum map_queues_vidmem_enum {
+       vidmem__mes_map_queues__uses_no_video_memory = 0,
+       vidmem__mes_map_queues__uses_video_memory = 1
+};
+
+enum map_queues_alloc_format_enum {
+       alloc_format__mes_map_queues__one_per_pipe = 0,
+       alloc_format__mes_map_queues__all_on_one_pipe = 1
+};
+
+enum map_queues_engine_sel_enum {
+       engine_sel__mes_map_queues__compute = 0,
+       engine_sel__mes_map_queues__sdma0 = 2,
+       engine_sel__mes_map_queues__sdma1 = 3
+};
+
+struct pm4_map_queues {
+       union {
+               union PM4_MES_TYPE_3_HEADER header;     /* header */
+               uint32_t ordinal1;
+       };
+
+       union {
+               struct {
+                       uint32_t reserved1:4;
+                       enum map_queues_queue_sel_enum queue_sel:2;
+                       uint32_t reserved2:2;
+                       uint32_t vmid:4;
+                       uint32_t reserved3:4;
+                       enum map_queues_vidmem_enum vidmem:2;
+                       uint32_t reserved4:6;
+                       enum map_queues_alloc_format_enum alloc_format:2;
+                       enum map_queues_engine_sel_enum engine_sel:3;
+                       uint32_t num_queues:3;
+               } bitfields2;
+               uint32_t ordinal2;
+       };
+
+       struct {
+               union {
+                       struct {
+                               uint32_t reserved5:2;
+                               uint32_t doorbell_offset:21;
+                               uint32_t reserved6:3;
+                               uint32_t queue:6;
+                       } bitfields3;
+                       uint32_t ordinal3;
+               };
+
+               uint32_t mqd_addr_lo;
+               uint32_t mqd_addr_hi;
+               uint32_t wptr_addr_lo;
+               uint32_t wptr_addr_hi;
+
+       } mes_map_queues_ordinals[1];   /* 1..N of these ordinal groups */
+
+};
+#endif
+
+/*--------------------MES_QUERY_STATUS--------------------*/
+
+#ifndef PM4_MES_QUERY_STATUS_DEFINED
+#define PM4_MES_QUERY_STATUS_DEFINED
+enum query_status_interrupt_sel_enum {
+       interrupt_sel__mes_query_status__completion_status = 0,
+       interrupt_sel__mes_query_status__process_status = 1,
+       interrupt_sel__mes_query_status__queue_status = 2
+};
+
+enum query_status_command_enum {
+       command__mes_query_status__interrupt_only = 0,
+       command__mes_query_status__fence_only_immediate = 1,
+       command__mes_query_status__fence_only_after_write_ack = 2,
+       command__mes_query_status__fence_wait_for_write_ack_send_interrupt = 3
+};
+
+enum query_status_engine_sel_enum {
+       engine_sel__mes_query_status__compute = 0,
+       engine_sel__mes_query_status__sdma0_queue = 2,
+       engine_sel__mes_query_status__sdma1_queue = 3
+};
+
+struct pm4_query_status {
+       union {
+               union PM4_MES_TYPE_3_HEADER header;     /* header */
+               uint32_t ordinal1;
+       };
+
+       union {
+               struct {
+                       uint32_t context_id:28;
+                       enum query_status_interrupt_sel_enum interrupt_sel:2;
+                       enum query_status_command_enum command:2;
+               } bitfields2;
+               uint32_t ordinal2;
+       };
+
+       union {
+               struct {
+                       uint32_t pasid:16;
+                       uint32_t reserved1:16;
+               } bitfields3a;
+               struct {
+                       uint32_t reserved2:2;
+                       uint32_t doorbell_offset:21;
+                       uint32_t reserved3:3;
+                       enum query_status_engine_sel_enum engine_sel:3;
+                       uint32_t reserved4:3;
+               } bitfields3b;
+               uint32_t ordinal3;
+       };
+
+       uint32_t addr_lo;
+       uint32_t addr_hi;
+       uint32_t data_lo;
+       uint32_t data_hi;
+};
+#endif
+
+/*--------------------MES_UNMAP_QUEUES--------------------*/
+
+#ifndef PM4_MES_UNMAP_QUEUES_DEFINED
+#define PM4_MES_UNMAP_QUEUES_DEFINED
+enum unmap_queues_action_enum {
+       action__mes_unmap_queues__preempt_queues = 0,
+       action__mes_unmap_queues__reset_queues = 1,
+       action__mes_unmap_queues__disable_process_queues = 2
+};
+
+enum unmap_queues_queue_sel_enum {
+       queue_sel__mes_unmap_queues__perform_request_on_specified_queues = 0,
+       queue_sel__mes_unmap_queues__perform_request_on_pasid_queues = 1,
+       queue_sel__mes_unmap_queues__perform_request_on_all_active_queues = 2
+};
+
+enum unmap_queues_engine_sel_enum {
+       engine_sel__mes_unmap_queues__compute = 0,
+       engine_sel__mes_unmap_queues__sdma0 = 2,
+       engine_sel__mes_unmap_queues__sdma1 = 3
+};
+
+struct pm4_unmap_queues {
+       union {
+               union PM4_MES_TYPE_3_HEADER header;     /* header */
+               uint32_t ordinal1;
+       };
+
+       union {
+               struct {
+                       enum unmap_queues_action_enum action:2;
+                       uint32_t reserved1:2;
+                       enum unmap_queues_queue_sel_enum queue_sel:2;
+                       uint32_t reserved2:20;
+                       enum unmap_queues_engine_sel_enum engine_sel:3;
+                       uint32_t num_queues:3;
+               } bitfields2;
+               uint32_t ordinal2;
+       };
+
+       union {
+               struct {
+                       uint32_t pasid:16;
+                       uint32_t reserved3:16;
+               } bitfields3a;
+               struct {
+                       uint32_t reserved4:2;
+                       uint32_t doorbell_offset0:21;
+                       uint32_t reserved5:9;
+               } bitfields3b;
+               uint32_t ordinal3;
+       };
+
+       union {
+               struct {
+                       uint32_t reserved6:2;
+                       uint32_t doorbell_offset1:21;
+                       uint32_t reserved7:9;
+               } bitfields4;
+               uint32_t ordinal4;
+       };
+
+       union {
+               struct {
+                       uint32_t reserved8:2;
+                       uint32_t doorbell_offset2:21;
+                       uint32_t reserved9:9;
+               } bitfields5;
+               uint32_t ordinal5;
+       };
+
+       union {
+               struct {
+                       uint32_t reserved10:2;
+                       uint32_t doorbell_offset3:21;
+                       uint32_t reserved11:9;
+               } bitfields6;
+               uint32_t ordinal6;
+       };
+
+};
+#endif
+
+enum {
+       CACHE_FLUSH_AND_INV_TS_EVENT = 0x00000014
+};
+
+#endif /* KFD_PM4_HEADERS_H_ */
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_pm4_opcodes.h b/drivers/gpu/drm/amd/amdkfd/kfd_pm4_opcodes.h
new file mode 100644 (file)
index 0000000..b72fa3b
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+
+#ifndef KFD_PM4_OPCODES_H
+#define KFD_PM4_OPCODES_H
+
+enum it_opcode_type {
+       IT_NOP                               = 0x10,
+       IT_SET_BASE                          = 0x11,
+       IT_CLEAR_STATE                       = 0x12,
+       IT_INDEX_BUFFER_SIZE                 = 0x13,
+       IT_DISPATCH_DIRECT                   = 0x15,
+       IT_DISPATCH_INDIRECT                 = 0x16,
+       IT_ATOMIC_GDS                        = 0x1D,
+       IT_OCCLUSION_QUERY                   = 0x1F,
+       IT_SET_PREDICATION                   = 0x20,
+       IT_REG_RMW                           = 0x21,
+       IT_COND_EXEC                         = 0x22,
+       IT_PRED_EXEC                         = 0x23,
+       IT_DRAW_INDIRECT                     = 0x24,
+       IT_DRAW_INDEX_INDIRECT               = 0x25,
+       IT_INDEX_BASE                        = 0x26,
+       IT_DRAW_INDEX_2                      = 0x27,
+       IT_CONTEXT_CONTROL                   = 0x28,
+       IT_INDEX_TYPE                        = 0x2A,
+       IT_DRAW_INDIRECT_MULTI               = 0x2C,
+       IT_DRAW_INDEX_AUTO                   = 0x2D,
+       IT_NUM_INSTANCES                     = 0x2F,
+       IT_DRAW_INDEX_MULTI_AUTO             = 0x30,
+       IT_INDIRECT_BUFFER_CNST              = 0x33,
+       IT_STRMOUT_BUFFER_UPDATE             = 0x34,
+       IT_DRAW_INDEX_OFFSET_2               = 0x35,
+       IT_DRAW_PREAMBLE                     = 0x36,
+       IT_WRITE_DATA                        = 0x37,
+       IT_DRAW_INDEX_INDIRECT_MULTI         = 0x38,
+       IT_MEM_SEMAPHORE                     = 0x39,
+       IT_COPY_DW                           = 0x3B,
+       IT_WAIT_REG_MEM                      = 0x3C,
+       IT_INDIRECT_BUFFER                   = 0x3F,
+       IT_COPY_DATA                         = 0x40,
+       IT_PFP_SYNC_ME                       = 0x42,
+       IT_SURFACE_SYNC                      = 0x43,
+       IT_COND_WRITE                        = 0x45,
+       IT_EVENT_WRITE                       = 0x46,
+       IT_EVENT_WRITE_EOP                   = 0x47,
+       IT_EVENT_WRITE_EOS                   = 0x48,
+       IT_RELEASE_MEM                       = 0x49,
+       IT_PREAMBLE_CNTL                     = 0x4A,
+       IT_DMA_DATA                          = 0x50,
+       IT_ACQUIRE_MEM                       = 0x58,
+       IT_REWIND                            = 0x59,
+       IT_LOAD_UCONFIG_REG                  = 0x5E,
+       IT_LOAD_SH_REG                       = 0x5F,
+       IT_LOAD_CONFIG_REG                   = 0x60,
+       IT_LOAD_CONTEXT_REG                  = 0x61,
+       IT_SET_CONFIG_REG                    = 0x68,
+       IT_SET_CONTEXT_REG                   = 0x69,
+       IT_SET_CONTEXT_REG_INDIRECT          = 0x73,
+       IT_SET_SH_REG                        = 0x76,
+       IT_SET_SH_REG_OFFSET                 = 0x77,
+       IT_SET_QUEUE_REG                     = 0x78,
+       IT_SET_UCONFIG_REG                   = 0x79,
+       IT_SCRATCH_RAM_WRITE                 = 0x7D,
+       IT_SCRATCH_RAM_READ                  = 0x7E,
+       IT_LOAD_CONST_RAM                    = 0x80,
+       IT_WRITE_CONST_RAM                   = 0x81,
+       IT_DUMP_CONST_RAM                    = 0x83,
+       IT_INCREMENT_CE_COUNTER              = 0x84,
+       IT_INCREMENT_DE_COUNTER              = 0x85,
+       IT_WAIT_ON_CE_COUNTER                = 0x86,
+       IT_WAIT_ON_DE_COUNTER_DIFF           = 0x88,
+       IT_SWITCH_BUFFER                     = 0x8B,
+       IT_SET_RESOURCES                     = 0xA0,
+       IT_MAP_PROCESS                       = 0xA1,
+       IT_MAP_QUEUES                        = 0xA2,
+       IT_UNMAP_QUEUES                      = 0xA3,
+       IT_QUERY_STATUS                      = 0xA4,
+       IT_RUN_LIST                          = 0xA5,
+};
+
+#define PM4_TYPE_0 0
+#define PM4_TYPE_2 2
+#define PM4_TYPE_3 3
+
+#endif /* KFD_PM4_OPCODES_H */
+
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
new file mode 100644 (file)
index 0000000..f9fb81e
--- /dev/null
@@ -0,0 +1,600 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef KFD_PRIV_H_INCLUDED
+#define KFD_PRIV_H_INCLUDED
+
+#include <linux/hashtable.h>
+#include <linux/mmu_notifier.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/atomic.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/kfd_ioctl.h>
+#include <kgd_kfd_interface.h>
+
+#define KFD_SYSFS_FILE_MODE 0444
+
+/*
+ * When working with cp scheduler we should assign the HIQ manually or via
+ * the radeon driver to a fixed hqd slot, here are the fixed HIQ hqd slot
+ * definitions for Kaveri. In Kaveri only the first ME queues participates
+ * in the cp scheduling taking that in mind we set the HIQ slot in the
+ * second ME.
+ */
+#define KFD_CIK_HIQ_PIPE 4
+#define KFD_CIK_HIQ_QUEUE 0
+
+/* GPU ID hash width in bits */
+#define KFD_GPU_ID_HASH_WIDTH 16
+
+/* Macro for allocating structures */
+#define kfd_alloc_struct(ptr_to_struct)        \
+       ((typeof(ptr_to_struct)) kzalloc(sizeof(*ptr_to_struct), GFP_KERNEL))
+
+/* Kernel module parameter to specify maximum number of supported processes */
+extern int max_num_of_processes;
+
+#define KFD_MAX_NUM_OF_PROCESSES_DEFAULT 32
+#define KFD_MAX_NUM_OF_PROCESSES 512
+
+/*
+ * Kernel module parameter to specify maximum number of supported queues
+ * per process
+ */
+extern int max_num_of_queues_per_process;
+
+#define KFD_MAX_NUM_OF_QUEUES_PER_PROCESS_DEFAULT 128
+#define KFD_MAX_NUM_OF_QUEUES_PER_PROCESS 1024
+
+#define KFD_KERNEL_QUEUE_SIZE 2048
+
+/* Kernel module parameter to specify the scheduling policy */
+extern int sched_policy;
+
+/**
+ * enum kfd_sched_policy
+ *
+ * @KFD_SCHED_POLICY_HWS: H/W scheduling policy known as command processor (cp)
+ * scheduling. In this scheduling mode we're using the firmware code to
+ * schedule the user mode queues and kernel queues such as HIQ and DIQ.
+ * the HIQ queue is used as a special queue that dispatches the configuration
+ * to the cp and the user mode queues list that are currently running.
+ * the DIQ queue is a debugging queue that dispatches debugging commands to the
+ * firmware.
+ * in this scheduling mode user mode queues over subscription feature is
+ * enabled.
+ *
+ * @KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION: The same as above but the over
+ * subscription feature disabled.
+ *
+ * @KFD_SCHED_POLICY_NO_HWS: no H/W scheduling policy is a mode which directly
+ * set the command processor registers and sets the queues "manually". This
+ * mode is used *ONLY* for debugging proposes.
+ *
+ */
+enum kfd_sched_policy {
+       KFD_SCHED_POLICY_HWS = 0,
+       KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION,
+       KFD_SCHED_POLICY_NO_HWS
+};
+
+enum cache_policy {
+       cache_policy_coherent,
+       cache_policy_noncoherent
+};
+
+struct kfd_device_info {
+       unsigned int max_pasid_bits;
+       size_t ih_ring_entry_size;
+       uint16_t mqd_size_aligned;
+};
+
+struct kfd_dev {
+       struct kgd_dev *kgd;
+
+       const struct kfd_device_info *device_info;
+       struct pci_dev *pdev;
+
+       unsigned int id;                /* topology stub index */
+
+       phys_addr_t doorbell_base;      /* Start of actual doorbells used by
+                                        * KFD. It is aligned for mapping
+                                        * into user mode
+                                        */
+       size_t doorbell_id_offset;      /* Doorbell offset (from KFD doorbell
+                                        * to HW doorbell, GFX reserved some
+                                        * at the start)
+                                        */
+       size_t doorbell_process_limit;  /* Number of processes we have doorbell
+                                        * space for.
+                                        */
+       u32 __iomem *doorbell_kernel_ptr; /* This is a pointer for a doorbells
+                                          * page used by kernel queue
+                                          */
+
+       struct kgd2kfd_shared_resources shared_resources;
+
+       void *interrupt_ring;
+       size_t interrupt_ring_size;
+       atomic_t interrupt_ring_rptr;
+       atomic_t interrupt_ring_wptr;
+       struct work_struct interrupt_work;
+       spinlock_t interrupt_lock;
+
+       /* QCM Device instance */
+       struct device_queue_manager *dqm;
+
+       bool init_complete;
+       /*
+        * Interrupts of interest to KFD are copied
+        * from the HW ring into a SW ring.
+        */
+       bool interrupts_active;
+};
+
+/* KGD2KFD callbacks */
+void kgd2kfd_exit(void);
+struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev);
+bool kgd2kfd_device_init(struct kfd_dev *kfd,
+                        const struct kgd2kfd_shared_resources *gpu_resources);
+void kgd2kfd_device_exit(struct kfd_dev *kfd);
+
+extern const struct kfd2kgd_calls *kfd2kgd;
+
+struct kfd_mem_obj {
+       void *bo;
+       uint64_t gpu_addr;
+       uint32_t *cpu_ptr;
+};
+
+enum kfd_mempool {
+       KFD_MEMPOOL_SYSTEM_CACHEABLE = 1,
+       KFD_MEMPOOL_SYSTEM_WRITECOMBINE = 2,
+       KFD_MEMPOOL_FRAMEBUFFER = 3,
+};
+
+/* Character device interface */
+int kfd_chardev_init(void);
+void kfd_chardev_exit(void);
+struct device *kfd_chardev(void);
+
+/**
+ * enum kfd_preempt_type_filter
+ *
+ * @KFD_PREEMPT_TYPE_FILTER_SINGLE_QUEUE: Preempts single queue.
+ *
+ * @KFD_PRERMPT_TYPE_FILTER_ALL_QUEUES: Preempts all queues in the
+ *                                             running queues list.
+ *
+ * @KFD_PRERMPT_TYPE_FILTER_BY_PASID: Preempts queues that belongs to
+ *                                             specific process.
+ *
+ */
+enum kfd_preempt_type_filter {
+       KFD_PREEMPT_TYPE_FILTER_SINGLE_QUEUE,
+       KFD_PREEMPT_TYPE_FILTER_ALL_QUEUES,
+       KFD_PREEMPT_TYPE_FILTER_BY_PASID
+};
+
+enum kfd_preempt_type {
+       KFD_PREEMPT_TYPE_WAVEFRONT,
+       KFD_PREEMPT_TYPE_WAVEFRONT_RESET
+};
+
+/**
+ * enum kfd_queue_type
+ *
+ * @KFD_QUEUE_TYPE_COMPUTE: Regular user mode queue type.
+ *
+ * @KFD_QUEUE_TYPE_SDMA: Sdma user mode queue type.
+ *
+ * @KFD_QUEUE_TYPE_HIQ: HIQ queue type.
+ *
+ * @KFD_QUEUE_TYPE_DIQ: DIQ queue type.
+ */
+enum kfd_queue_type  {
+       KFD_QUEUE_TYPE_COMPUTE,
+       KFD_QUEUE_TYPE_SDMA,
+       KFD_QUEUE_TYPE_HIQ,
+       KFD_QUEUE_TYPE_DIQ
+};
+
+enum kfd_queue_format {
+       KFD_QUEUE_FORMAT_PM4,
+       KFD_QUEUE_FORMAT_AQL
+};
+
+/**
+ * struct queue_properties
+ *
+ * @type: The queue type.
+ *
+ * @queue_id: Queue identifier.
+ *
+ * @queue_address: Queue ring buffer address.
+ *
+ * @queue_size: Queue ring buffer size.
+ *
+ * @priority: Defines the queue priority relative to other queues in the
+ * process.
+ * This is just an indication and HW scheduling may override the priority as
+ * necessary while keeping the relative prioritization.
+ * the priority granularity is from 0 to f which f is the highest priority.
+ * currently all queues are initialized with the highest priority.
+ *
+ * @queue_percent: This field is partially implemented and currently a zero in
+ * this field defines that the queue is non active.
+ *
+ * @read_ptr: User space address which points to the number of dwords the
+ * cp read from the ring buffer. This field updates automatically by the H/W.
+ *
+ * @write_ptr: Defines the number of dwords written to the ring buffer.
+ *
+ * @doorbell_ptr: This field aim is to notify the H/W of new packet written to
+ * the queue ring buffer. This field should be similar to write_ptr and the user
+ * should update this field after he updated the write_ptr.
+ *
+ * @doorbell_off: The doorbell offset in the doorbell pci-bar.
+ *
+ * @is_interop: Defines if this is a interop queue. Interop queue means that the
+ * queue can access both graphics and compute resources.
+ *
+ * @is_active: Defines if the queue is active or not.
+ *
+ * @vmid: If the scheduling mode is no cp scheduling the field defines the vmid
+ * of the queue.
+ *
+ * This structure represents the queue properties for each queue no matter if
+ * it's user mode or kernel mode queue.
+ *
+ */
+struct queue_properties {
+       enum kfd_queue_type type;
+       enum kfd_queue_format format;
+       unsigned int queue_id;
+       uint64_t queue_address;
+       uint64_t  queue_size;
+       uint32_t priority;
+       uint32_t queue_percent;
+       uint32_t *read_ptr;
+       uint32_t *write_ptr;
+       uint32_t __iomem *doorbell_ptr;
+       uint32_t doorbell_off;
+       bool is_interop;
+       bool is_active;
+       /* Not relevant for user mode queues in cp scheduling */
+       unsigned int vmid;
+};
+
+/**
+ * struct queue
+ *
+ * @list: Queue linked list.
+ *
+ * @mqd: The queue MQD.
+ *
+ * @mqd_mem_obj: The MQD local gpu memory object.
+ *
+ * @gart_mqd_addr: The MQD gart mc address.
+ *
+ * @properties: The queue properties.
+ *
+ * @mec: Used only in no cp scheduling mode and identifies to micro engine id
+ * that the queue should be execute on.
+ *
+ * @pipe: Used only in no cp scheduling mode and identifies the queue's pipe id.
+ *
+ * @queue: Used only in no cp scheduliong mode and identifies the queue's slot.
+ *
+ * @process: The kfd process that created this queue.
+ *
+ * @device: The kfd device that created this queue.
+ *
+ * This structure represents user mode compute queues.
+ * It contains all the necessary data to handle such queues.
+ *
+ */
+
+struct queue {
+       struct list_head list;
+       void *mqd;
+       struct kfd_mem_obj *mqd_mem_obj;
+       uint64_t gart_mqd_addr;
+       struct queue_properties properties;
+
+       uint32_t mec;
+       uint32_t pipe;
+       uint32_t queue;
+
+       struct kfd_process      *process;
+       struct kfd_dev          *device;
+};
+
+/*
+ * Please read the kfd_mqd_manager.h description.
+ */
+enum KFD_MQD_TYPE {
+       KFD_MQD_TYPE_CIK_COMPUTE = 0, /* for no cp scheduling */
+       KFD_MQD_TYPE_CIK_HIQ, /* for hiq */
+       KFD_MQD_TYPE_CIK_CP, /* for cp queues and diq */
+       KFD_MQD_TYPE_CIK_SDMA, /* for sdma queues */
+       KFD_MQD_TYPE_MAX
+};
+
+struct scheduling_resources {
+       unsigned int vmid_mask;
+       enum kfd_queue_type type;
+       uint64_t queue_mask;
+       uint64_t gws_mask;
+       uint32_t oac_mask;
+       uint32_t gds_heap_base;
+       uint32_t gds_heap_size;
+};
+
+struct process_queue_manager {
+       /* data */
+       struct kfd_process      *process;
+       unsigned int            num_concurrent_processes;
+       struct list_head        queues;
+       unsigned long           *queue_slot_bitmap;
+};
+
+struct qcm_process_device {
+       /* The Device Queue Manager that owns this data */
+       struct device_queue_manager *dqm;
+       struct process_queue_manager *pqm;
+       /* Device Queue Manager lock */
+       struct mutex *lock;
+       /* Queues list */
+       struct list_head queues_list;
+       struct list_head priv_queue_list;
+
+       unsigned int queue_count;
+       unsigned int vmid;
+       bool is_debug;
+       /*
+        * All the memory management data should be here too
+        */
+       uint64_t gds_context_area;
+       uint32_t sh_mem_config;
+       uint32_t sh_mem_bases;
+       uint32_t sh_mem_ape1_base;
+       uint32_t sh_mem_ape1_limit;
+       uint32_t page_table_base;
+       uint32_t gds_size;
+       uint32_t num_gws;
+       uint32_t num_oac;
+};
+
+/* Data that is per-process-per device. */
+struct kfd_process_device {
+       /*
+        * List of all per-device data for a process.
+        * Starts from kfd_process.per_device_data.
+        */
+       struct list_head per_device_list;
+
+       /* The device that owns this data. */
+       struct kfd_dev *dev;
+
+
+       /* per-process-per device QCM data structure */
+       struct qcm_process_device qpd;
+
+       /*Apertures*/
+       uint64_t lds_base;
+       uint64_t lds_limit;
+       uint64_t gpuvm_base;
+       uint64_t gpuvm_limit;
+       uint64_t scratch_base;
+       uint64_t scratch_limit;
+
+       /* Is this process/pasid bound to this device? (amd_iommu_bind_pasid) */
+       bool bound;
+};
+
+#define qpd_to_pdd(x) container_of(x, struct kfd_process_device, qpd)
+
+/* Process data */
+struct kfd_process {
+       /*
+        * kfd_process are stored in an mm_struct*->kfd_process*
+        * hash table (kfd_processes in kfd_process.c)
+        */
+       struct hlist_node kfd_processes;
+
+       struct mm_struct *mm;
+
+       struct mutex mutex;
+
+       /*
+        * In any process, the thread that started main() is the lead
+        * thread and outlives the rest.
+        * It is here because amd_iommu_bind_pasid wants a task_struct.
+        */
+       struct task_struct *lead_thread;
+
+       /* We want to receive a notification when the mm_struct is destroyed */
+       struct mmu_notifier mmu_notifier;
+
+       /* Use for delayed freeing of kfd_process structure */
+       struct rcu_head rcu;
+
+       unsigned int pasid;
+
+       /*
+        * List of kfd_process_device structures,
+        * one for each device the process is using.
+        */
+       struct list_head per_device_data;
+
+       struct process_queue_manager pqm;
+
+       /* The process's queues. */
+       size_t queue_array_size;
+
+       /* Size is queue_array_size, up to MAX_PROCESS_QUEUES. */
+       struct kfd_queue **queues;
+
+       unsigned long allocated_queue_bitmap[DIV_ROUND_UP(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS, BITS_PER_LONG)];
+
+       /*Is the user space process 32 bit?*/
+       bool is_32bit_user_mode;
+};
+
+void kfd_process_create_wq(void);
+void kfd_process_destroy_wq(void);
+struct kfd_process *kfd_create_process(const struct task_struct *);
+struct kfd_process *kfd_get_process(const struct task_struct *);
+
+struct kfd_process_device *kfd_bind_process_to_device(struct kfd_dev *dev,
+                                                       struct kfd_process *p);
+void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid);
+struct kfd_process_device *kfd_get_process_device_data(struct kfd_dev *dev,
+                                                       struct kfd_process *p,
+                                                       int create_pdd);
+
+/* Process device data iterator */
+struct kfd_process_device *kfd_get_first_process_device_data(struct kfd_process *p);
+struct kfd_process_device *kfd_get_next_process_device_data(struct kfd_process *p,
+                                               struct kfd_process_device *pdd);
+bool kfd_has_process_device_data(struct kfd_process *p);
+
+/* PASIDs */
+int kfd_pasid_init(void);
+void kfd_pasid_exit(void);
+bool kfd_set_pasid_limit(unsigned int new_limit);
+unsigned int kfd_get_pasid_limit(void);
+unsigned int kfd_pasid_alloc(void);
+void kfd_pasid_free(unsigned int pasid);
+
+/* Doorbells */
+void kfd_doorbell_init(struct kfd_dev *kfd);
+int kfd_doorbell_mmap(struct kfd_process *process, struct vm_area_struct *vma);
+u32 __iomem *kfd_get_kernel_doorbell(struct kfd_dev *kfd,
+                                       unsigned int *doorbell_off);
+void kfd_release_kernel_doorbell(struct kfd_dev *kfd, u32 __iomem *db_addr);
+u32 read_kernel_doorbell(u32 __iomem *db);
+void write_kernel_doorbell(u32 __iomem *db, u32 value);
+unsigned int kfd_queue_id_to_doorbell(struct kfd_dev *kfd,
+                                       struct kfd_process *process,
+                                       unsigned int queue_id);
+
+extern struct device *kfd_device;
+
+/* Topology */
+int kfd_topology_init(void);
+void kfd_topology_shutdown(void);
+int kfd_topology_add_device(struct kfd_dev *gpu);
+int kfd_topology_remove_device(struct kfd_dev *gpu);
+struct kfd_dev *kfd_device_by_id(uint32_t gpu_id);
+struct kfd_dev *kfd_device_by_pci_dev(const struct pci_dev *pdev);
+struct kfd_dev *kfd_topology_enum_kfd_devices(uint8_t idx);
+
+/* Interrupts */
+int kfd_interrupt_init(struct kfd_dev *dev);
+void kfd_interrupt_exit(struct kfd_dev *dev);
+void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry);
+bool enqueue_ih_ring_entry(struct kfd_dev *kfd,        const void *ih_ring_entry);
+
+/* Power Management */
+void kgd2kfd_suspend(struct kfd_dev *kfd);
+int kgd2kfd_resume(struct kfd_dev *kfd);
+
+/* amdkfd Apertures */
+int kfd_init_apertures(struct kfd_process *process);
+
+/* Queue Context Management */
+inline uint32_t lower_32(uint64_t x);
+inline uint32_t upper_32(uint64_t x);
+
+int init_queue(struct queue **q, struct queue_properties properties);
+void uninit_queue(struct queue *q);
+void print_queue_properties(struct queue_properties *q);
+void print_queue(struct queue *q);
+
+struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type,
+                                       struct kfd_dev *dev);
+struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev);
+void device_queue_manager_uninit(struct device_queue_manager *dqm);
+struct kernel_queue *kernel_queue_init(struct kfd_dev *dev,
+                                       enum kfd_queue_type type);
+void kernel_queue_uninit(struct kernel_queue *kq);
+
+/* Process Queue Manager */
+struct process_queue_node {
+       struct queue *q;
+       struct kernel_queue *kq;
+       struct list_head process_queue_list;
+};
+
+int pqm_init(struct process_queue_manager *pqm, struct kfd_process *p);
+void pqm_uninit(struct process_queue_manager *pqm);
+int pqm_create_queue(struct process_queue_manager *pqm,
+                           struct kfd_dev *dev,
+                           struct file *f,
+                           struct queue_properties *properties,
+                           unsigned int flags,
+                           enum kfd_queue_type type,
+                           unsigned int *qid);
+int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid);
+int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid,
+                       struct queue_properties *p);
+
+/* Packet Manager */
+
+#define KFD_HIQ_TIMEOUT (500)
+
+#define KFD_FENCE_COMPLETED (100)
+#define KFD_FENCE_INIT   (10)
+#define KFD_UNMAP_LATENCY (150)
+
+struct packet_manager {
+       struct device_queue_manager *dqm;
+       struct kernel_queue *priv_queue;
+       struct mutex lock;
+       bool allocated;
+       struct kfd_mem_obj *ib_buffer_obj;
+};
+
+int pm_init(struct packet_manager *pm, struct device_queue_manager *dqm);
+void pm_uninit(struct packet_manager *pm);
+int pm_send_set_resources(struct packet_manager *pm,
+                               struct scheduling_resources *res);
+int pm_send_runlist(struct packet_manager *pm, struct list_head *dqm_queues);
+int pm_send_query_status(struct packet_manager *pm, uint64_t fence_address,
+                               uint32_t fence_value);
+
+int pm_send_unmap_queue(struct packet_manager *pm, enum kfd_queue_type type,
+                       enum kfd_preempt_type_filter mode,
+                       uint32_t filter_param, bool reset,
+                       unsigned int sdma_engine);
+
+void pm_release_ib(struct packet_manager *pm);
+
+uint64_t kfd_get_number_elems(struct kfd_dev *kfd);
+phys_addr_t kfd_get_process_doorbells(struct kfd_dev *dev,
+                                       struct kfd_process *process);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
new file mode 100644 (file)
index 0000000..b4f49ac
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/mutex.h>
+#include <linux/log2.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/amd-iommu.h>
+#include <linux/notifier.h>
+struct mm_struct;
+
+#include "kfd_priv.h"
+
+/*
+ * Initial size for the array of queues.
+ * The allocated size is doubled each time
+ * it is exceeded up to MAX_PROCESS_QUEUES.
+ */
+#define INITIAL_QUEUE_ARRAY_SIZE 16
+
+/*
+ * List of struct kfd_process (field kfd_process).
+ * Unique/indexed by mm_struct*
+ */
+#define KFD_PROCESS_TABLE_SIZE 5 /* bits: 32 entries */
+static DEFINE_HASHTABLE(kfd_processes_table, KFD_PROCESS_TABLE_SIZE);
+static DEFINE_MUTEX(kfd_processes_mutex);
+
+DEFINE_STATIC_SRCU(kfd_processes_srcu);
+
+static struct workqueue_struct *kfd_process_wq;
+
+struct kfd_process_release_work {
+       struct work_struct kfd_work;
+       struct kfd_process *p;
+};
+
+static struct kfd_process *find_process(const struct task_struct *thread);
+static struct kfd_process *create_process(const struct task_struct *thread);
+
+void kfd_process_create_wq(void)
+{
+       if (!kfd_process_wq)
+               kfd_process_wq = create_workqueue("kfd_process_wq");
+}
+
+void kfd_process_destroy_wq(void)
+{
+       if (kfd_process_wq) {
+               flush_workqueue(kfd_process_wq);
+               destroy_workqueue(kfd_process_wq);
+               kfd_process_wq = NULL;
+       }
+}
+
+struct kfd_process *kfd_create_process(const struct task_struct *thread)
+{
+       struct kfd_process *process;
+
+       BUG_ON(!kfd_process_wq);
+
+       if (thread->mm == NULL)
+               return ERR_PTR(-EINVAL);
+
+       /* Only the pthreads threading model is supported. */
+       if (thread->group_leader->mm != thread->mm)
+               return ERR_PTR(-EINVAL);
+
+       /* Take mmap_sem because we call __mmu_notifier_register inside */
+       down_write(&thread->mm->mmap_sem);
+
+       /*
+        * take kfd processes mutex before starting of process creation
+        * so there won't be a case where two threads of the same process
+        * create two kfd_process structures
+        */
+       mutex_lock(&kfd_processes_mutex);
+
+       /* A prior open of /dev/kfd could have already created the process. */
+       process = find_process(thread);
+       if (process)
+               pr_debug("kfd: process already found\n");
+
+       if (!process)
+               process = create_process(thread);
+
+       mutex_unlock(&kfd_processes_mutex);
+
+       up_write(&thread->mm->mmap_sem);
+
+       return process;
+}
+
+struct kfd_process *kfd_get_process(const struct task_struct *thread)
+{
+       struct kfd_process *process;
+
+       if (thread->mm == NULL)
+               return ERR_PTR(-EINVAL);
+
+       /* Only the pthreads threading model is supported. */
+       if (thread->group_leader->mm != thread->mm)
+               return ERR_PTR(-EINVAL);
+
+       process = find_process(thread);
+
+       return process;
+}
+
+static struct kfd_process *find_process_by_mm(const struct mm_struct *mm)
+{
+       struct kfd_process *process;
+
+       hash_for_each_possible_rcu(kfd_processes_table, process,
+                                       kfd_processes, (uintptr_t)mm)
+               if (process->mm == mm)
+                       return process;
+
+       return NULL;
+}
+
+static struct kfd_process *find_process(const struct task_struct *thread)
+{
+       struct kfd_process *p;
+       int idx;
+
+       idx = srcu_read_lock(&kfd_processes_srcu);
+       p = find_process_by_mm(thread->mm);
+       srcu_read_unlock(&kfd_processes_srcu, idx);
+
+       return p;
+}
+
+static void kfd_process_wq_release(struct work_struct *work)
+{
+       struct kfd_process_release_work *my_work;
+       struct kfd_process_device *pdd, *temp;
+       struct kfd_process *p;
+
+       my_work = (struct kfd_process_release_work *) work;
+
+       p = my_work->p;
+
+       mutex_lock(&p->mutex);
+
+       list_for_each_entry_safe(pdd, temp, &p->per_device_data,
+                                                       per_device_list) {
+               amd_iommu_unbind_pasid(pdd->dev->pdev, p->pasid);
+               list_del(&pdd->per_device_list);
+
+               kfree(pdd);
+       }
+
+       kfd_pasid_free(p->pasid);
+
+       mutex_unlock(&p->mutex);
+
+       mutex_destroy(&p->mutex);
+
+       kfree(p->queues);
+
+       kfree(p);
+
+       kfree((void *)work);
+}
+
+static void kfd_process_destroy_delayed(struct rcu_head *rcu)
+{
+       struct kfd_process_release_work *work;
+       struct kfd_process *p;
+
+       BUG_ON(!kfd_process_wq);
+
+       p = container_of(rcu, struct kfd_process, rcu);
+       BUG_ON(atomic_read(&p->mm->mm_count) <= 0);
+
+       mmdrop(p->mm);
+
+       work = (struct kfd_process_release_work *)
+               kmalloc(sizeof(struct kfd_process_release_work), GFP_KERNEL);
+
+       if (work) {
+               INIT_WORK((struct work_struct *) work, kfd_process_wq_release);
+               work->p = p;
+               queue_work(kfd_process_wq, (struct work_struct *) work);
+       }
+}
+
+static void kfd_process_notifier_release(struct mmu_notifier *mn,
+                                       struct mm_struct *mm)
+{
+       struct kfd_process *p;
+
+       /*
+        * The kfd_process structure can not be free because the
+        * mmu_notifier srcu is read locked
+        */
+       p = container_of(mn, struct kfd_process, mmu_notifier);
+       BUG_ON(p->mm != mm);
+
+       mutex_lock(&kfd_processes_mutex);
+       hash_del_rcu(&p->kfd_processes);
+       mutex_unlock(&kfd_processes_mutex);
+       synchronize_srcu(&kfd_processes_srcu);
+
+       mutex_lock(&p->mutex);
+
+       /* In case our notifier is called before IOMMU notifier */
+       pqm_uninit(&p->pqm);
+
+       mutex_unlock(&p->mutex);
+
+       /*
+        * Because we drop mm_count inside kfd_process_destroy_delayed
+        * and because the mmu_notifier_unregister function also drop
+        * mm_count we need to take an extra count here.
+        */
+       atomic_inc(&p->mm->mm_count);
+       mmu_notifier_unregister_no_release(&p->mmu_notifier, p->mm);
+       mmu_notifier_call_srcu(&p->rcu, &kfd_process_destroy_delayed);
+}
+
+static const struct mmu_notifier_ops kfd_process_mmu_notifier_ops = {
+       .release = kfd_process_notifier_release,
+};
+
+static struct kfd_process *create_process(const struct task_struct *thread)
+{
+       struct kfd_process *process;
+       int err = -ENOMEM;
+
+       process = kzalloc(sizeof(*process), GFP_KERNEL);
+
+       if (!process)
+               goto err_alloc_process;
+
+       process->queues = kmalloc_array(INITIAL_QUEUE_ARRAY_SIZE,
+                                       sizeof(process->queues[0]), GFP_KERNEL);
+       if (!process->queues)
+               goto err_alloc_queues;
+
+       process->pasid = kfd_pasid_alloc();
+       if (process->pasid == 0)
+               goto err_alloc_pasid;
+
+       mutex_init(&process->mutex);
+
+       process->mm = thread->mm;
+
+       /* register notifier */
+       process->mmu_notifier.ops = &kfd_process_mmu_notifier_ops;
+       err = __mmu_notifier_register(&process->mmu_notifier, process->mm);
+       if (err)
+               goto err_mmu_notifier;
+
+       hash_add_rcu(kfd_processes_table, &process->kfd_processes,
+                       (uintptr_t)process->mm);
+
+       process->lead_thread = thread->group_leader;
+
+       process->queue_array_size = INITIAL_QUEUE_ARRAY_SIZE;
+
+       INIT_LIST_HEAD(&process->per_device_data);
+
+       err = pqm_init(&process->pqm, process);
+       if (err != 0)
+               goto err_process_pqm_init;
+
+       return process;
+
+err_process_pqm_init:
+       hash_del_rcu(&process->kfd_processes);
+       synchronize_rcu();
+       mmu_notifier_unregister_no_release(&process->mmu_notifier, process->mm);
+err_mmu_notifier:
+       kfd_pasid_free(process->pasid);
+err_alloc_pasid:
+       kfree(process->queues);
+err_alloc_queues:
+       kfree(process);
+err_alloc_process:
+       return ERR_PTR(err);
+}
+
+struct kfd_process_device *kfd_get_process_device_data(struct kfd_dev *dev,
+                                                       struct kfd_process *p,
+                                                       int create_pdd)
+{
+       struct kfd_process_device *pdd = NULL;
+
+       list_for_each_entry(pdd, &p->per_device_data, per_device_list)
+               if (pdd->dev == dev)
+                       return pdd;
+
+       if (create_pdd) {
+               pdd = kzalloc(sizeof(*pdd), GFP_KERNEL);
+               if (pdd != NULL) {
+                       pdd->dev = dev;
+                       INIT_LIST_HEAD(&pdd->qpd.queues_list);
+                       INIT_LIST_HEAD(&pdd->qpd.priv_queue_list);
+                       pdd->qpd.dqm = dev->dqm;
+                       list_add(&pdd->per_device_list, &p->per_device_data);
+               }
+       }
+
+       return pdd;
+}
+
+/*
+ * Direct the IOMMU to bind the process (specifically the pasid->mm)
+ * to the device.
+ * Unbinding occurs when the process dies or the device is removed.
+ *
+ * Assumes that the process lock is held.
+ */
+struct kfd_process_device *kfd_bind_process_to_device(struct kfd_dev *dev,
+                                                       struct kfd_process *p)
+{
+       struct kfd_process_device *pdd = kfd_get_process_device_data(dev, p, 1);
+       int err;
+
+       if (pdd == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       if (pdd->bound)
+               return pdd;
+
+       err = amd_iommu_bind_pasid(dev->pdev, p->pasid, p->lead_thread);
+       if (err < 0)
+               return ERR_PTR(err);
+
+       pdd->bound = true;
+
+       return pdd;
+}
+
+void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid)
+{
+       struct kfd_process *p;
+       struct kfd_process_device *pdd;
+       int idx, i;
+
+       BUG_ON(dev == NULL);
+
+       idx = srcu_read_lock(&kfd_processes_srcu);
+
+       hash_for_each_rcu(kfd_processes_table, i, p, kfd_processes)
+               if (p->pasid == pasid)
+                       break;
+
+       srcu_read_unlock(&kfd_processes_srcu, idx);
+
+       BUG_ON(p->pasid != pasid);
+
+       mutex_lock(&p->mutex);
+
+       pqm_uninit(&p->pqm);
+
+       pdd = kfd_get_process_device_data(dev, p, 0);
+
+       /*
+        * Just mark pdd as unbound, because we still need it to call
+        * amd_iommu_unbind_pasid() in when the process exits.
+        * We don't call amd_iommu_unbind_pasid() here
+        * because the IOMMU called us.
+        */
+       if (pdd)
+               pdd->bound = false;
+
+       mutex_unlock(&p->mutex);
+}
+
+struct kfd_process_device *kfd_get_first_process_device_data(struct kfd_process *p)
+{
+       return list_first_entry(&p->per_device_data,
+                               struct kfd_process_device,
+                               per_device_list);
+}
+
+struct kfd_process_device *kfd_get_next_process_device_data(struct kfd_process *p,
+                                               struct kfd_process_device *pdd)
+{
+       if (list_is_last(&pdd->per_device_list, &p->per_device_data))
+               return NULL;
+       return list_next_entry(pdd, per_device_list);
+}
+
+bool kfd_has_process_device_data(struct kfd_process *p)
+{
+       return !(list_empty(&p->per_device_data));
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
new file mode 100644 (file)
index 0000000..4752678
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/list.h>
+#include "kfd_device_queue_manager.h"
+#include "kfd_priv.h"
+#include "kfd_kernel_queue.h"
+
+static inline struct process_queue_node *get_queue_by_qid(
+                       struct process_queue_manager *pqm, unsigned int qid)
+{
+       struct process_queue_node *pqn;
+
+       BUG_ON(!pqm);
+
+       list_for_each_entry(pqn, &pqm->queues, process_queue_list) {
+               if (pqn->q && pqn->q->properties.queue_id == qid)
+                       return pqn;
+               if (pqn->kq && pqn->kq->queue->properties.queue_id == qid)
+                       return pqn;
+       }
+
+       return NULL;
+}
+
+static int find_available_queue_slot(struct process_queue_manager *pqm,
+                                       unsigned int *qid)
+{
+       unsigned long found;
+
+       BUG_ON(!pqm || !qid);
+
+       pr_debug("kfd: in %s\n", __func__);
+
+       found = find_first_zero_bit(pqm->queue_slot_bitmap,
+                       max_num_of_queues_per_process);
+
+       pr_debug("kfd: the new slot id %lu\n", found);
+
+       if (found >= max_num_of_queues_per_process) {
+               pr_info("amdkfd: Can not open more queues for process with pasid %d\n",
+                               pqm->process->pasid);
+               return -ENOMEM;
+       }
+
+       set_bit(found, pqm->queue_slot_bitmap);
+       *qid = found;
+
+       return 0;
+}
+
+int pqm_init(struct process_queue_manager *pqm, struct kfd_process *p)
+{
+       BUG_ON(!pqm);
+
+       INIT_LIST_HEAD(&pqm->queues);
+       pqm->queue_slot_bitmap =
+                       kzalloc(DIV_ROUND_UP(max_num_of_queues_per_process,
+                                       BITS_PER_BYTE), GFP_KERNEL);
+       if (pqm->queue_slot_bitmap == NULL)
+               return -ENOMEM;
+       pqm->process = p;
+
+       return 0;
+}
+
+void pqm_uninit(struct process_queue_manager *pqm)
+{
+       int retval;
+       struct process_queue_node *pqn, *next;
+
+       BUG_ON(!pqm);
+
+       pr_debug("In func %s\n", __func__);
+
+       list_for_each_entry_safe(pqn, next, &pqm->queues, process_queue_list) {
+               retval = pqm_destroy_queue(
+                               pqm,
+                               (pqn->q != NULL) ?
+                                       pqn->q->properties.queue_id :
+                                       pqn->kq->queue->properties.queue_id);
+
+               if (retval != 0) {
+                       pr_err("kfd: failed to destroy queue\n");
+                       return;
+               }
+       }
+       kfree(pqm->queue_slot_bitmap);
+       pqm->queue_slot_bitmap = NULL;
+}
+
+static int create_cp_queue(struct process_queue_manager *pqm,
+                               struct kfd_dev *dev, struct queue **q,
+                               struct queue_properties *q_properties,
+                               struct file *f, unsigned int qid)
+{
+       int retval;
+
+       retval = 0;
+
+       /* Doorbell initialized in user space*/
+       q_properties->doorbell_ptr = NULL;
+
+       q_properties->doorbell_off =
+                       kfd_queue_id_to_doorbell(dev, pqm->process, qid);
+
+       /* let DQM handle it*/
+       q_properties->vmid = 0;
+       q_properties->queue_id = qid;
+       q_properties->type = KFD_QUEUE_TYPE_COMPUTE;
+
+       retval = init_queue(q, *q_properties);
+       if (retval != 0)
+               goto err_init_queue;
+
+       (*q)->device = dev;
+       (*q)->process = pqm->process;
+
+       pr_debug("kfd: PQM After init queue");
+
+       return retval;
+
+err_init_queue:
+       return retval;
+}
+
+int pqm_create_queue(struct process_queue_manager *pqm,
+                           struct kfd_dev *dev,
+                           struct file *f,
+                           struct queue_properties *properties,
+                           unsigned int flags,
+                           enum kfd_queue_type type,
+                           unsigned int *qid)
+{
+       int retval;
+       struct kfd_process_device *pdd;
+       struct queue_properties q_properties;
+       struct queue *q;
+       struct process_queue_node *pqn;
+       struct kernel_queue *kq;
+
+       BUG_ON(!pqm || !dev || !properties || !qid);
+
+       memset(&q_properties, 0, sizeof(struct queue_properties));
+       memcpy(&q_properties, properties, sizeof(struct queue_properties));
+       q = NULL;
+       kq = NULL;
+
+       pdd = kfd_get_process_device_data(dev, pqm->process, 1);
+       BUG_ON(!pdd);
+
+       retval = find_available_queue_slot(pqm, qid);
+       if (retval != 0)
+               return retval;
+
+       if (list_empty(&pqm->queues)) {
+               pdd->qpd.pqm = pqm;
+               dev->dqm->register_process(dev->dqm, &pdd->qpd);
+       }
+
+       pqn = kzalloc(sizeof(struct process_queue_node), GFP_KERNEL);
+       if (!pqn) {
+               retval = -ENOMEM;
+               goto err_allocate_pqn;
+       }
+
+       switch (type) {
+       case KFD_QUEUE_TYPE_COMPUTE:
+               /* check if there is over subscription */
+               if ((sched_policy == KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION) &&
+               ((dev->dqm->processes_count >= VMID_PER_DEVICE) ||
+               (dev->dqm->queue_count >= PIPE_PER_ME_CP_SCHEDULING * QUEUES_PER_PIPE))) {
+                       pr_err("kfd: over-subscription is not allowed in radeon_kfd.sched_policy == 1\n");
+                       retval = -EPERM;
+                       goto err_create_queue;
+               }
+
+               retval = create_cp_queue(pqm, dev, &q, &q_properties, f, *qid);
+               if (retval != 0)
+                       goto err_create_queue;
+               pqn->q = q;
+               pqn->kq = NULL;
+               retval = dev->dqm->create_queue(dev->dqm, q, &pdd->qpd,
+                                               &q->properties.vmid);
+               print_queue(q);
+               break;
+       case KFD_QUEUE_TYPE_DIQ:
+               kq = kernel_queue_init(dev, KFD_QUEUE_TYPE_DIQ);
+               if (kq == NULL) {
+                       retval = -ENOMEM;
+                       goto err_create_queue;
+               }
+               kq->queue->properties.queue_id = *qid;
+               pqn->kq = kq;
+               pqn->q = NULL;
+               retval = dev->dqm->create_kernel_queue(dev->dqm, kq, &pdd->qpd);
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       if (retval != 0) {
+               pr_err("kfd: error dqm create queue\n");
+               goto err_create_queue;
+       }
+
+       pr_debug("kfd: PQM After DQM create queue\n");
+
+       list_add(&pqn->process_queue_list, &pqm->queues);
+
+       if (q) {
+               *properties = q->properties;
+               pr_debug("kfd: PQM done creating queue\n");
+               print_queue_properties(properties);
+       }
+
+       return retval;
+
+err_create_queue:
+       kfree(pqn);
+err_allocate_pqn:
+       clear_bit(*qid, pqm->queue_slot_bitmap);
+       return retval;
+}
+
+int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid)
+{
+       struct process_queue_node *pqn;
+       struct kfd_process_device *pdd;
+       struct device_queue_manager *dqm;
+       struct kfd_dev *dev;
+       int retval;
+
+       dqm = NULL;
+
+       BUG_ON(!pqm);
+       retval = 0;
+
+       pr_debug("kfd: In Func %s\n", __func__);
+
+       pqn = get_queue_by_qid(pqm, qid);
+       if (pqn == NULL) {
+               pr_err("kfd: queue id does not match any known queue\n");
+               return -EINVAL;
+       }
+
+       dev = NULL;
+       if (pqn->kq)
+               dev = pqn->kq->dev;
+       if (pqn->q)
+               dev = pqn->q->device;
+       BUG_ON(!dev);
+
+       pdd = kfd_get_process_device_data(dev, pqm->process, 1);
+       BUG_ON(!pdd);
+
+       if (pqn->kq) {
+               /* destroy kernel queue (DIQ) */
+               dqm = pqn->kq->dev->dqm;
+               dqm->destroy_kernel_queue(dqm, pqn->kq, &pdd->qpd);
+               kernel_queue_uninit(pqn->kq);
+       }
+
+       if (pqn->q) {
+               dqm = pqn->q->device->dqm;
+               retval = dqm->destroy_queue(dqm, &pdd->qpd, pqn->q);
+               if (retval != 0)
+                       return retval;
+
+               uninit_queue(pqn->q);
+       }
+
+       list_del(&pqn->process_queue_list);
+       kfree(pqn);
+       clear_bit(qid, pqm->queue_slot_bitmap);
+
+       if (list_empty(&pqm->queues))
+               dqm->unregister_process(dqm, &pdd->qpd);
+
+       return retval;
+}
+
+int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid,
+                       struct queue_properties *p)
+{
+       int retval;
+       struct process_queue_node *pqn;
+
+       BUG_ON(!pqm);
+
+       pqn = get_queue_by_qid(pqm, qid);
+       BUG_ON(!pqn);
+
+       pqn->q->properties.queue_address = p->queue_address;
+       pqn->q->properties.queue_size = p->queue_size;
+       pqn->q->properties.queue_percent = p->queue_percent;
+       pqn->q->properties.priority = p->priority;
+
+       retval = pqn->q->device->dqm->update_queue(pqn->q->device->dqm, pqn->q);
+       if (retval != 0)
+               return retval;
+
+       return 0;
+}
+
+static __attribute__((unused)) struct kernel_queue *pqm_get_kernel_queue(
+                                       struct process_queue_manager *pqm,
+                                       unsigned int qid)
+{
+       struct process_queue_node *pqn;
+
+       BUG_ON(!pqm);
+
+       pqn = get_queue_by_qid(pqm, qid);
+       if (pqn && pqn->kq)
+               return pqn->kq;
+
+       return NULL;
+}
+
+
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c
new file mode 100644 (file)
index 0000000..9a0c90b
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/slab.h>
+#include "kfd_priv.h"
+
+void print_queue_properties(struct queue_properties *q)
+{
+       if (!q)
+               return;
+
+       pr_debug("Printing queue properties:\n");
+       pr_debug("Queue Type: %u\n", q->type);
+       pr_debug("Queue Size: %llu\n", q->queue_size);
+       pr_debug("Queue percent: %u\n", q->queue_percent);
+       pr_debug("Queue Address: 0x%llX\n", q->queue_address);
+       pr_debug("Queue Id: %u\n", q->queue_id);
+       pr_debug("Queue Process Vmid: %u\n", q->vmid);
+       pr_debug("Queue Read Pointer: 0x%p\n", q->read_ptr);
+       pr_debug("Queue Write Pointer: 0x%p\n", q->write_ptr);
+       pr_debug("Queue Doorbell Pointer: 0x%p\n", q->doorbell_ptr);
+       pr_debug("Queue Doorbell Offset: %u\n", q->doorbell_off);
+}
+
+void print_queue(struct queue *q)
+{
+       if (!q)
+               return;
+       pr_debug("Printing queue:\n");
+       pr_debug("Queue Type: %u\n", q->properties.type);
+       pr_debug("Queue Size: %llu\n", q->properties.queue_size);
+       pr_debug("Queue percent: %u\n", q->properties.queue_percent);
+       pr_debug("Queue Address: 0x%llX\n", q->properties.queue_address);
+       pr_debug("Queue Id: %u\n", q->properties.queue_id);
+       pr_debug("Queue Process Vmid: %u\n", q->properties.vmid);
+       pr_debug("Queue Read Pointer: 0x%p\n", q->properties.read_ptr);
+       pr_debug("Queue Write Pointer: 0x%p\n", q->properties.write_ptr);
+       pr_debug("Queue Doorbell Pointer: 0x%p\n", q->properties.doorbell_ptr);
+       pr_debug("Queue Doorbell Offset: %u\n", q->properties.doorbell_off);
+       pr_debug("Queue MQD Address: 0x%p\n", q->mqd);
+       pr_debug("Queue MQD Gart: 0x%llX\n", q->gart_mqd_addr);
+       pr_debug("Queue Process Address: 0x%p\n", q->process);
+       pr_debug("Queue Device Address: 0x%p\n", q->device);
+}
+
+int init_queue(struct queue **q, struct queue_properties properties)
+{
+       struct queue *tmp;
+
+       BUG_ON(!q);
+
+       tmp = kzalloc(sizeof(struct queue), GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       memcpy(&tmp->properties, &properties, sizeof(struct queue_properties));
+
+       *q = tmp;
+       return 0;
+}
+
+void uninit_queue(struct queue *q)
+{
+       kfree(q);
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
new file mode 100644 (file)
index 0000000..5733e28
--- /dev/null
@@ -0,0 +1,1235 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/acpi.h>
+#include <linux/hash.h>
+#include <linux/cpufreq.h>
+
+#include "kfd_priv.h"
+#include "kfd_crat.h"
+#include "kfd_topology.h"
+
+static struct list_head topology_device_list;
+static int topology_crat_parsed;
+static struct kfd_system_properties sys_props;
+
+static DECLARE_RWSEM(topology_lock);
+
+struct kfd_dev *kfd_device_by_id(uint32_t gpu_id)
+{
+       struct kfd_topology_device *top_dev;
+       struct kfd_dev *device = NULL;
+
+       down_read(&topology_lock);
+
+       list_for_each_entry(top_dev, &topology_device_list, list)
+               if (top_dev->gpu_id == gpu_id) {
+                       device = top_dev->gpu;
+                       break;
+               }
+
+       up_read(&topology_lock);
+
+       return device;
+}
+
+struct kfd_dev *kfd_device_by_pci_dev(const struct pci_dev *pdev)
+{
+       struct kfd_topology_device *top_dev;
+       struct kfd_dev *device = NULL;
+
+       down_read(&topology_lock);
+
+       list_for_each_entry(top_dev, &topology_device_list, list)
+               if (top_dev->gpu->pdev == pdev) {
+                       device = top_dev->gpu;
+                       break;
+               }
+
+       up_read(&topology_lock);
+
+       return device;
+}
+
+static int kfd_topology_get_crat_acpi(void *crat_image, size_t *size)
+{
+       struct acpi_table_header *crat_table;
+       acpi_status status;
+
+       if (!size)
+               return -EINVAL;
+
+       /*
+        * Fetch the CRAT table from ACPI
+        */
+       status = acpi_get_table(CRAT_SIGNATURE, 0, &crat_table);
+       if (status == AE_NOT_FOUND) {
+               pr_warn("CRAT table not found\n");
+               return -ENODATA;
+       } else if (ACPI_FAILURE(status)) {
+               const char *err = acpi_format_exception(status);
+
+               pr_err("CRAT table error: %s\n", err);
+               return -EINVAL;
+       }
+
+       if (*size >= crat_table->length && crat_image != NULL)
+               memcpy(crat_image, crat_table, crat_table->length);
+
+       *size = crat_table->length;
+
+       return 0;
+}
+
+static void kfd_populated_cu_info_cpu(struct kfd_topology_device *dev,
+               struct crat_subtype_computeunit *cu)
+{
+       BUG_ON(!dev);
+       BUG_ON(!cu);
+
+       dev->node_props.cpu_cores_count = cu->num_cpu_cores;
+       dev->node_props.cpu_core_id_base = cu->processor_id_low;
+       if (cu->hsa_capability & CRAT_CU_FLAGS_IOMMU_PRESENT)
+               dev->node_props.capability |= HSA_CAP_ATS_PRESENT;
+
+       pr_info("CU CPU: cores=%d id_base=%d\n", cu->num_cpu_cores,
+                       cu->processor_id_low);
+}
+
+static void kfd_populated_cu_info_gpu(struct kfd_topology_device *dev,
+               struct crat_subtype_computeunit *cu)
+{
+       BUG_ON(!dev);
+       BUG_ON(!cu);
+
+       dev->node_props.simd_id_base = cu->processor_id_low;
+       dev->node_props.simd_count = cu->num_simd_cores;
+       dev->node_props.lds_size_in_kb = cu->lds_size_in_kb;
+       dev->node_props.max_waves_per_simd = cu->max_waves_simd;
+       dev->node_props.wave_front_size = cu->wave_front_size;
+       dev->node_props.mem_banks_count = cu->num_banks;
+       dev->node_props.array_count = cu->num_arrays;
+       dev->node_props.cu_per_simd_array = cu->num_cu_per_array;
+       dev->node_props.simd_per_cu = cu->num_simd_per_cu;
+       dev->node_props.max_slots_scratch_cu = cu->max_slots_scatch_cu;
+       if (cu->hsa_capability & CRAT_CU_FLAGS_HOT_PLUGGABLE)
+               dev->node_props.capability |= HSA_CAP_HOT_PLUGGABLE;
+       pr_info("CU GPU: simds=%d id_base=%d\n", cu->num_simd_cores,
+                               cu->processor_id_low);
+}
+
+/* kfd_parse_subtype_cu is called when the topology mutex is already acquired */
+static int kfd_parse_subtype_cu(struct crat_subtype_computeunit *cu)
+{
+       struct kfd_topology_device *dev;
+       int i = 0;
+
+       BUG_ON(!cu);
+
+       pr_info("Found CU entry in CRAT table with proximity_domain=%d caps=%x\n",
+                       cu->proximity_domain, cu->hsa_capability);
+       list_for_each_entry(dev, &topology_device_list, list) {
+               if (cu->proximity_domain == i) {
+                       if (cu->flags & CRAT_CU_FLAGS_CPU_PRESENT)
+                               kfd_populated_cu_info_cpu(dev, cu);
+
+                       if (cu->flags & CRAT_CU_FLAGS_GPU_PRESENT)
+                               kfd_populated_cu_info_gpu(dev, cu);
+                       break;
+               }
+               i++;
+       }
+
+       return 0;
+}
+
+/*
+ * kfd_parse_subtype_mem is called when the topology mutex is
+ * already acquired
+ */
+static int kfd_parse_subtype_mem(struct crat_subtype_memory *mem)
+{
+       struct kfd_mem_properties *props;
+       struct kfd_topology_device *dev;
+       int i = 0;
+
+       BUG_ON(!mem);
+
+       pr_info("Found memory entry in CRAT table with proximity_domain=%d\n",
+                       mem->promixity_domain);
+       list_for_each_entry(dev, &topology_device_list, list) {
+               if (mem->promixity_domain == i) {
+                       props = kfd_alloc_struct(props);
+                       if (props == NULL)
+                               return -ENOMEM;
+
+                       if (dev->node_props.cpu_cores_count == 0)
+                               props->heap_type = HSA_MEM_HEAP_TYPE_FB_PRIVATE;
+                       else
+                               props->heap_type = HSA_MEM_HEAP_TYPE_SYSTEM;
+
+                       if (mem->flags & CRAT_MEM_FLAGS_HOT_PLUGGABLE)
+                               props->flags |= HSA_MEM_FLAGS_HOT_PLUGGABLE;
+                       if (mem->flags & CRAT_MEM_FLAGS_NON_VOLATILE)
+                               props->flags |= HSA_MEM_FLAGS_NON_VOLATILE;
+
+                       props->size_in_bytes =
+                               ((uint64_t)mem->length_high << 32) +
+                                                       mem->length_low;
+                       props->width = mem->width;
+
+                       dev->mem_bank_count++;
+                       list_add_tail(&props->list, &dev->mem_props);
+
+                       break;
+               }
+               i++;
+       }
+
+       return 0;
+}
+
+/*
+ * kfd_parse_subtype_cache is called when the topology mutex
+ * is already acquired
+ */
+static int kfd_parse_subtype_cache(struct crat_subtype_cache *cache)
+{
+       struct kfd_cache_properties *props;
+       struct kfd_topology_device *dev;
+       uint32_t id;
+
+       BUG_ON(!cache);
+
+       id = cache->processor_id_low;
+
+       pr_info("Found cache entry in CRAT table with processor_id=%d\n", id);
+       list_for_each_entry(dev, &topology_device_list, list)
+               if (id == dev->node_props.cpu_core_id_base ||
+                   id == dev->node_props.simd_id_base) {
+                       props = kfd_alloc_struct(props);
+                       if (props == NULL)
+                               return -ENOMEM;
+
+                       props->processor_id_low = id;
+                       props->cache_level = cache->cache_level;
+                       props->cache_size = cache->cache_size;
+                       props->cacheline_size = cache->cache_line_size;
+                       props->cachelines_per_tag = cache->lines_per_tag;
+                       props->cache_assoc = cache->associativity;
+                       props->cache_latency = cache->cache_latency;
+
+                       if (cache->flags & CRAT_CACHE_FLAGS_DATA_CACHE)
+                               props->cache_type |= HSA_CACHE_TYPE_DATA;
+                       if (cache->flags & CRAT_CACHE_FLAGS_INST_CACHE)
+                               props->cache_type |= HSA_CACHE_TYPE_INSTRUCTION;
+                       if (cache->flags & CRAT_CACHE_FLAGS_CPU_CACHE)
+                               props->cache_type |= HSA_CACHE_TYPE_CPU;
+                       if (cache->flags & CRAT_CACHE_FLAGS_SIMD_CACHE)
+                               props->cache_type |= HSA_CACHE_TYPE_HSACU;
+
+                       dev->cache_count++;
+                       dev->node_props.caches_count++;
+                       list_add_tail(&props->list, &dev->cache_props);
+
+                       break;
+               }
+
+       return 0;
+}
+
+/*
+ * kfd_parse_subtype_iolink is called when the topology mutex
+ * is already acquired
+ */
+static int kfd_parse_subtype_iolink(struct crat_subtype_iolink *iolink)
+{
+       struct kfd_iolink_properties *props;
+       struct kfd_topology_device *dev;
+       uint32_t i = 0;
+       uint32_t id_from;
+       uint32_t id_to;
+
+       BUG_ON(!iolink);
+
+       id_from = iolink->proximity_domain_from;
+       id_to = iolink->proximity_domain_to;
+
+       pr_info("Found IO link entry in CRAT table with id_from=%d\n", id_from);
+       list_for_each_entry(dev, &topology_device_list, list) {
+               if (id_from == i) {
+                       props = kfd_alloc_struct(props);
+                       if (props == NULL)
+                               return -ENOMEM;
+
+                       props->node_from = id_from;
+                       props->node_to = id_to;
+                       props->ver_maj = iolink->version_major;
+                       props->ver_min = iolink->version_minor;
+
+                       /*
+                        * weight factor (derived from CDIR), currently always 1
+                        */
+                       props->weight = 1;
+
+                       props->min_latency = iolink->minimum_latency;
+                       props->max_latency = iolink->maximum_latency;
+                       props->min_bandwidth = iolink->minimum_bandwidth_mbs;
+                       props->max_bandwidth = iolink->maximum_bandwidth_mbs;
+                       props->rec_transfer_size =
+                                       iolink->recommended_transfer_size;
+
+                       dev->io_link_count++;
+                       dev->node_props.io_links_count++;
+                       list_add_tail(&props->list, &dev->io_link_props);
+
+                       break;
+               }
+               i++;
+       }
+
+       return 0;
+}
+
+static int kfd_parse_subtype(struct crat_subtype_generic *sub_type_hdr)
+{
+       struct crat_subtype_computeunit *cu;
+       struct crat_subtype_memory *mem;
+       struct crat_subtype_cache *cache;
+       struct crat_subtype_iolink *iolink;
+       int ret = 0;
+
+       BUG_ON(!sub_type_hdr);
+
+       switch (sub_type_hdr->type) {
+       case CRAT_SUBTYPE_COMPUTEUNIT_AFFINITY:
+               cu = (struct crat_subtype_computeunit *)sub_type_hdr;
+               ret = kfd_parse_subtype_cu(cu);
+               break;
+       case CRAT_SUBTYPE_MEMORY_AFFINITY:
+               mem = (struct crat_subtype_memory *)sub_type_hdr;
+               ret = kfd_parse_subtype_mem(mem);
+               break;
+       case CRAT_SUBTYPE_CACHE_AFFINITY:
+               cache = (struct crat_subtype_cache *)sub_type_hdr;
+               ret = kfd_parse_subtype_cache(cache);
+               break;
+       case CRAT_SUBTYPE_TLB_AFFINITY:
+               /*
+                * For now, nothing to do here
+                */
+               pr_info("Found TLB entry in CRAT table (not processing)\n");
+               break;
+       case CRAT_SUBTYPE_CCOMPUTE_AFFINITY:
+               /*
+                * For now, nothing to do here
+                */
+               pr_info("Found CCOMPUTE entry in CRAT table (not processing)\n");
+               break;
+       case CRAT_SUBTYPE_IOLINK_AFFINITY:
+               iolink = (struct crat_subtype_iolink *)sub_type_hdr;
+               ret = kfd_parse_subtype_iolink(iolink);
+               break;
+       default:
+               pr_warn("Unknown subtype (%d) in CRAT\n",
+                               sub_type_hdr->type);
+       }
+
+       return ret;
+}
+
+static void kfd_release_topology_device(struct kfd_topology_device *dev)
+{
+       struct kfd_mem_properties *mem;
+       struct kfd_cache_properties *cache;
+       struct kfd_iolink_properties *iolink;
+
+       BUG_ON(!dev);
+
+       list_del(&dev->list);
+
+       while (dev->mem_props.next != &dev->mem_props) {
+               mem = container_of(dev->mem_props.next,
+                               struct kfd_mem_properties, list);
+               list_del(&mem->list);
+               kfree(mem);
+       }
+
+       while (dev->cache_props.next != &dev->cache_props) {
+               cache = container_of(dev->cache_props.next,
+                               struct kfd_cache_properties, list);
+               list_del(&cache->list);
+               kfree(cache);
+       }
+
+       while (dev->io_link_props.next != &dev->io_link_props) {
+               iolink = container_of(dev->io_link_props.next,
+                               struct kfd_iolink_properties, list);
+               list_del(&iolink->list);
+               kfree(iolink);
+       }
+
+       kfree(dev);
+
+       sys_props.num_devices--;
+}
+
+static void kfd_release_live_view(void)
+{
+       struct kfd_topology_device *dev;
+
+       while (topology_device_list.next != &topology_device_list) {
+               dev = container_of(topology_device_list.next,
+                                struct kfd_topology_device, list);
+               kfd_release_topology_device(dev);
+}
+
+       memset(&sys_props, 0, sizeof(sys_props));
+}
+
+static struct kfd_topology_device *kfd_create_topology_device(void)
+{
+       struct kfd_topology_device *dev;
+
+       dev = kfd_alloc_struct(dev);
+       if (dev == NULL) {
+               pr_err("No memory to allocate a topology device");
+               return NULL;
+       }
+
+       INIT_LIST_HEAD(&dev->mem_props);
+       INIT_LIST_HEAD(&dev->cache_props);
+       INIT_LIST_HEAD(&dev->io_link_props);
+
+       list_add_tail(&dev->list, &topology_device_list);
+       sys_props.num_devices++;
+
+       return dev;
+}
+
+static int kfd_parse_crat_table(void *crat_image)
+{
+       struct kfd_topology_device *top_dev;
+       struct crat_subtype_generic *sub_type_hdr;
+       uint16_t node_id;
+       int ret;
+       struct crat_header *crat_table = (struct crat_header *)crat_image;
+       uint16_t num_nodes;
+       uint32_t image_len;
+
+       if (!crat_image)
+               return -EINVAL;
+
+       num_nodes = crat_table->num_domains;
+       image_len = crat_table->length;
+
+       pr_info("Parsing CRAT table with %d nodes\n", num_nodes);
+
+       for (node_id = 0; node_id < num_nodes; node_id++) {
+               top_dev = kfd_create_topology_device();
+               if (!top_dev) {
+                       kfd_release_live_view();
+                       return -ENOMEM;
+               }
+       }
+
+       sys_props.platform_id =
+               (*((uint64_t *)crat_table->oem_id)) & CRAT_OEMID_64BIT_MASK;
+       sys_props.platform_oem = *((uint64_t *)crat_table->oem_table_id);
+       sys_props.platform_rev = crat_table->revision;
+
+       sub_type_hdr = (struct crat_subtype_generic *)(crat_table+1);
+       while ((char *)sub_type_hdr + sizeof(struct crat_subtype_generic) <
+                       ((char *)crat_image) + image_len) {
+               if (sub_type_hdr->flags & CRAT_SUBTYPE_FLAGS_ENABLED) {
+                       ret = kfd_parse_subtype(sub_type_hdr);
+                       if (ret != 0) {
+                               kfd_release_live_view();
+                               return ret;
+                       }
+               }
+
+               sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr +
+                               sub_type_hdr->length);
+       }
+
+       sys_props.generation_count++;
+       topology_crat_parsed = 1;
+
+       return 0;
+}
+
+
+#define sysfs_show_gen_prop(buffer, fmt, ...) \
+               snprintf(buffer, PAGE_SIZE, "%s"fmt, buffer, __VA_ARGS__)
+#define sysfs_show_32bit_prop(buffer, name, value) \
+               sysfs_show_gen_prop(buffer, "%s %u\n", name, value)
+#define sysfs_show_64bit_prop(buffer, name, value) \
+               sysfs_show_gen_prop(buffer, "%s %llu\n", name, value)
+#define sysfs_show_32bit_val(buffer, value) \
+               sysfs_show_gen_prop(buffer, "%u\n", value)
+#define sysfs_show_str_val(buffer, value) \
+               sysfs_show_gen_prop(buffer, "%s\n", value)
+
+static ssize_t sysprops_show(struct kobject *kobj, struct attribute *attr,
+               char *buffer)
+{
+       ssize_t ret;
+
+       /* Making sure that the buffer is an empty string */
+       buffer[0] = 0;
+
+       if (attr == &sys_props.attr_genid) {
+               ret = sysfs_show_32bit_val(buffer, sys_props.generation_count);
+       } else if (attr == &sys_props.attr_props) {
+               sysfs_show_64bit_prop(buffer, "platform_oem",
+                               sys_props.platform_oem);
+               sysfs_show_64bit_prop(buffer, "platform_id",
+                               sys_props.platform_id);
+               ret = sysfs_show_64bit_prop(buffer, "platform_rev",
+                               sys_props.platform_rev);
+       } else {
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static const struct sysfs_ops sysprops_ops = {
+       .show = sysprops_show,
+};
+
+static struct kobj_type sysprops_type = {
+       .sysfs_ops = &sysprops_ops,
+};
+
+static ssize_t iolink_show(struct kobject *kobj, struct attribute *attr,
+               char *buffer)
+{
+       ssize_t ret;
+       struct kfd_iolink_properties *iolink;
+
+       /* Making sure that the buffer is an empty string */
+       buffer[0] = 0;
+
+       iolink = container_of(attr, struct kfd_iolink_properties, attr);
+       sysfs_show_32bit_prop(buffer, "type", iolink->iolink_type);
+       sysfs_show_32bit_prop(buffer, "version_major", iolink->ver_maj);
+       sysfs_show_32bit_prop(buffer, "version_minor", iolink->ver_min);
+       sysfs_show_32bit_prop(buffer, "node_from", iolink->node_from);
+       sysfs_show_32bit_prop(buffer, "node_to", iolink->node_to);
+       sysfs_show_32bit_prop(buffer, "weight", iolink->weight);
+       sysfs_show_32bit_prop(buffer, "min_latency", iolink->min_latency);
+       sysfs_show_32bit_prop(buffer, "max_latency", iolink->max_latency);
+       sysfs_show_32bit_prop(buffer, "min_bandwidth", iolink->min_bandwidth);
+       sysfs_show_32bit_prop(buffer, "max_bandwidth", iolink->max_bandwidth);
+       sysfs_show_32bit_prop(buffer, "recommended_transfer_size",
+                       iolink->rec_transfer_size);
+       ret = sysfs_show_32bit_prop(buffer, "flags", iolink->flags);
+
+       return ret;
+}
+
+static const struct sysfs_ops iolink_ops = {
+       .show = iolink_show,
+};
+
+static struct kobj_type iolink_type = {
+       .sysfs_ops = &iolink_ops,
+};
+
+static ssize_t mem_show(struct kobject *kobj, struct attribute *attr,
+               char *buffer)
+{
+       ssize_t ret;
+       struct kfd_mem_properties *mem;
+
+       /* Making sure that the buffer is an empty string */
+       buffer[0] = 0;
+
+       mem = container_of(attr, struct kfd_mem_properties, attr);
+       sysfs_show_32bit_prop(buffer, "heap_type", mem->heap_type);
+       sysfs_show_64bit_prop(buffer, "size_in_bytes", mem->size_in_bytes);
+       sysfs_show_32bit_prop(buffer, "flags", mem->flags);
+       sysfs_show_32bit_prop(buffer, "width", mem->width);
+       ret = sysfs_show_32bit_prop(buffer, "mem_clk_max", mem->mem_clk_max);
+
+       return ret;
+}
+
+static const struct sysfs_ops mem_ops = {
+       .show = mem_show,
+};
+
+static struct kobj_type mem_type = {
+       .sysfs_ops = &mem_ops,
+};
+
+static ssize_t kfd_cache_show(struct kobject *kobj, struct attribute *attr,
+               char *buffer)
+{
+       ssize_t ret;
+       uint32_t i;
+       struct kfd_cache_properties *cache;
+
+       /* Making sure that the buffer is an empty string */
+       buffer[0] = 0;
+
+       cache = container_of(attr, struct kfd_cache_properties, attr);
+       sysfs_show_32bit_prop(buffer, "processor_id_low",
+                       cache->processor_id_low);
+       sysfs_show_32bit_prop(buffer, "level", cache->cache_level);
+       sysfs_show_32bit_prop(buffer, "size", cache->cache_size);
+       sysfs_show_32bit_prop(buffer, "cache_line_size", cache->cacheline_size);
+       sysfs_show_32bit_prop(buffer, "cache_lines_per_tag",
+                       cache->cachelines_per_tag);
+       sysfs_show_32bit_prop(buffer, "association", cache->cache_assoc);
+       sysfs_show_32bit_prop(buffer, "latency", cache->cache_latency);
+       sysfs_show_32bit_prop(buffer, "type", cache->cache_type);
+       snprintf(buffer, PAGE_SIZE, "%ssibling_map ", buffer);
+       for (i = 0; i < KFD_TOPOLOGY_CPU_SIBLINGS; i++)
+               ret = snprintf(buffer, PAGE_SIZE, "%s%d%s",
+                               buffer, cache->sibling_map[i],
+                               (i == KFD_TOPOLOGY_CPU_SIBLINGS-1) ?
+                                               "\n" : ",");
+
+       return ret;
+}
+
+static const struct sysfs_ops cache_ops = {
+       .show = kfd_cache_show,
+};
+
+static struct kobj_type cache_type = {
+       .sysfs_ops = &cache_ops,
+};
+
+static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
+               char *buffer)
+{
+       ssize_t ret;
+       struct kfd_topology_device *dev;
+       char public_name[KFD_TOPOLOGY_PUBLIC_NAME_SIZE];
+       uint32_t i;
+
+       /* Making sure that the buffer is an empty string */
+       buffer[0] = 0;
+
+       if (strcmp(attr->name, "gpu_id") == 0) {
+               dev = container_of(attr, struct kfd_topology_device,
+                               attr_gpuid);
+               ret = sysfs_show_32bit_val(buffer, dev->gpu_id);
+       } else if (strcmp(attr->name, "name") == 0) {
+               dev = container_of(attr, struct kfd_topology_device,
+                               attr_name);
+               for (i = 0; i < KFD_TOPOLOGY_PUBLIC_NAME_SIZE; i++) {
+                       public_name[i] =
+                                       (char)dev->node_props.marketing_name[i];
+                       if (dev->node_props.marketing_name[i] == 0)
+                               break;
+               }
+               public_name[KFD_TOPOLOGY_PUBLIC_NAME_SIZE-1] = 0x0;
+               ret = sysfs_show_str_val(buffer, public_name);
+       } else {
+               dev = container_of(attr, struct kfd_topology_device,
+                               attr_props);
+               sysfs_show_32bit_prop(buffer, "cpu_cores_count",
+                               dev->node_props.cpu_cores_count);
+               sysfs_show_32bit_prop(buffer, "simd_count",
+                               dev->node_props.simd_count);
+
+               if (dev->mem_bank_count < dev->node_props.mem_banks_count) {
+                       pr_warn("kfd: mem_banks_count truncated from %d to %d\n",
+                                       dev->node_props.mem_banks_count,
+                                       dev->mem_bank_count);
+                       sysfs_show_32bit_prop(buffer, "mem_banks_count",
+                                       dev->mem_bank_count);
+               } else {
+                       sysfs_show_32bit_prop(buffer, "mem_banks_count",
+                                       dev->node_props.mem_banks_count);
+               }
+
+               sysfs_show_32bit_prop(buffer, "caches_count",
+                               dev->node_props.caches_count);
+               sysfs_show_32bit_prop(buffer, "io_links_count",
+                               dev->node_props.io_links_count);
+               sysfs_show_32bit_prop(buffer, "cpu_core_id_base",
+                               dev->node_props.cpu_core_id_base);
+               sysfs_show_32bit_prop(buffer, "simd_id_base",
+                               dev->node_props.simd_id_base);
+               sysfs_show_32bit_prop(buffer, "capability",
+                               dev->node_props.capability);
+               sysfs_show_32bit_prop(buffer, "max_waves_per_simd",
+                               dev->node_props.max_waves_per_simd);
+               sysfs_show_32bit_prop(buffer, "lds_size_in_kb",
+                               dev->node_props.lds_size_in_kb);
+               sysfs_show_32bit_prop(buffer, "gds_size_in_kb",
+                               dev->node_props.gds_size_in_kb);
+               sysfs_show_32bit_prop(buffer, "wave_front_size",
+                               dev->node_props.wave_front_size);
+               sysfs_show_32bit_prop(buffer, "array_count",
+                               dev->node_props.array_count);
+               sysfs_show_32bit_prop(buffer, "simd_arrays_per_engine",
+                               dev->node_props.simd_arrays_per_engine);
+               sysfs_show_32bit_prop(buffer, "cu_per_simd_array",
+                               dev->node_props.cu_per_simd_array);
+               sysfs_show_32bit_prop(buffer, "simd_per_cu",
+                               dev->node_props.simd_per_cu);
+               sysfs_show_32bit_prop(buffer, "max_slots_scratch_cu",
+                               dev->node_props.max_slots_scratch_cu);
+               sysfs_show_32bit_prop(buffer, "engine_id",
+                               dev->node_props.engine_id);
+               sysfs_show_32bit_prop(buffer, "vendor_id",
+                               dev->node_props.vendor_id);
+               sysfs_show_32bit_prop(buffer, "device_id",
+                               dev->node_props.device_id);
+               sysfs_show_32bit_prop(buffer, "location_id",
+                               dev->node_props.location_id);
+
+               if (dev->gpu) {
+                       sysfs_show_32bit_prop(buffer, "max_engine_clk_fcompute",
+                                       kfd2kgd->get_max_engine_clock_in_mhz(
+                                               dev->gpu->kgd));
+                       sysfs_show_64bit_prop(buffer, "local_mem_size",
+                                       kfd2kgd->get_vmem_size(dev->gpu->kgd));
+               }
+
+               ret = sysfs_show_32bit_prop(buffer, "max_engine_clk_ccompute",
+                               cpufreq_quick_get_max(0)/1000);
+       }
+
+       return ret;
+}
+
+static const struct sysfs_ops node_ops = {
+       .show = node_show,
+};
+
+static struct kobj_type node_type = {
+       .sysfs_ops = &node_ops,
+};
+
+static void kfd_remove_sysfs_file(struct kobject *kobj, struct attribute *attr)
+{
+       sysfs_remove_file(kobj, attr);
+       kobject_del(kobj);
+       kobject_put(kobj);
+}
+
+static void kfd_remove_sysfs_node_entry(struct kfd_topology_device *dev)
+{
+       struct kfd_iolink_properties *iolink;
+       struct kfd_cache_properties *cache;
+       struct kfd_mem_properties *mem;
+
+       BUG_ON(!dev);
+
+       if (dev->kobj_iolink) {
+               list_for_each_entry(iolink, &dev->io_link_props, list)
+                       if (iolink->kobj) {
+                               kfd_remove_sysfs_file(iolink->kobj,
+                                                       &iolink->attr);
+                               iolink->kobj = NULL;
+                       }
+               kobject_del(dev->kobj_iolink);
+               kobject_put(dev->kobj_iolink);
+               dev->kobj_iolink = NULL;
+       }
+
+       if (dev->kobj_cache) {
+               list_for_each_entry(cache, &dev->cache_props, list)
+                       if (cache->kobj) {
+                               kfd_remove_sysfs_file(cache->kobj,
+                                                       &cache->attr);
+                               cache->kobj = NULL;
+                       }
+               kobject_del(dev->kobj_cache);
+               kobject_put(dev->kobj_cache);
+               dev->kobj_cache = NULL;
+       }
+
+       if (dev->kobj_mem) {
+               list_for_each_entry(mem, &dev->mem_props, list)
+                       if (mem->kobj) {
+                               kfd_remove_sysfs_file(mem->kobj, &mem->attr);
+                               mem->kobj = NULL;
+                       }
+               kobject_del(dev->kobj_mem);
+               kobject_put(dev->kobj_mem);
+               dev->kobj_mem = NULL;
+       }
+
+       if (dev->kobj_node) {
+               sysfs_remove_file(dev->kobj_node, &dev->attr_gpuid);
+               sysfs_remove_file(dev->kobj_node, &dev->attr_name);
+               sysfs_remove_file(dev->kobj_node, &dev->attr_props);
+               kobject_del(dev->kobj_node);
+               kobject_put(dev->kobj_node);
+               dev->kobj_node = NULL;
+       }
+}
+
+static int kfd_build_sysfs_node_entry(struct kfd_topology_device *dev,
+               uint32_t id)
+{
+       struct kfd_iolink_properties *iolink;
+       struct kfd_cache_properties *cache;
+       struct kfd_mem_properties *mem;
+       int ret;
+       uint32_t i;
+
+       BUG_ON(!dev);
+
+       /*
+        * Creating the sysfs folders
+        */
+       BUG_ON(dev->kobj_node);
+       dev->kobj_node = kfd_alloc_struct(dev->kobj_node);
+       if (!dev->kobj_node)
+               return -ENOMEM;
+
+       ret = kobject_init_and_add(dev->kobj_node, &node_type,
+                       sys_props.kobj_nodes, "%d", id);
+       if (ret < 0)
+               return ret;
+
+       dev->kobj_mem = kobject_create_and_add("mem_banks", dev->kobj_node);
+       if (!dev->kobj_mem)
+               return -ENOMEM;
+
+       dev->kobj_cache = kobject_create_and_add("caches", dev->kobj_node);
+       if (!dev->kobj_cache)
+               return -ENOMEM;
+
+       dev->kobj_iolink = kobject_create_and_add("io_links", dev->kobj_node);
+       if (!dev->kobj_iolink)
+               return -ENOMEM;
+
+       /*
+        * Creating sysfs files for node properties
+        */
+       dev->attr_gpuid.name = "gpu_id";
+       dev->attr_gpuid.mode = KFD_SYSFS_FILE_MODE;
+       sysfs_attr_init(&dev->attr_gpuid);
+       dev->attr_name.name = "name";
+       dev->attr_name.mode = KFD_SYSFS_FILE_MODE;
+       sysfs_attr_init(&dev->attr_name);
+       dev->attr_props.name = "properties";
+       dev->attr_props.mode = KFD_SYSFS_FILE_MODE;
+       sysfs_attr_init(&dev->attr_props);
+       ret = sysfs_create_file(dev->kobj_node, &dev->attr_gpuid);
+       if (ret < 0)
+               return ret;
+       ret = sysfs_create_file(dev->kobj_node, &dev->attr_name);
+       if (ret < 0)
+               return ret;
+       ret = sysfs_create_file(dev->kobj_node, &dev->attr_props);
+       if (ret < 0)
+               return ret;
+
+       i = 0;
+       list_for_each_entry(mem, &dev->mem_props, list) {
+               mem->kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
+               if (!mem->kobj)
+                       return -ENOMEM;
+               ret = kobject_init_and_add(mem->kobj, &mem_type,
+                               dev->kobj_mem, "%d", i);
+               if (ret < 0)
+                       return ret;
+
+               mem->attr.name = "properties";
+               mem->attr.mode = KFD_SYSFS_FILE_MODE;
+               sysfs_attr_init(&mem->attr);
+               ret = sysfs_create_file(mem->kobj, &mem->attr);
+               if (ret < 0)
+                       return ret;
+               i++;
+       }
+
+       i = 0;
+       list_for_each_entry(cache, &dev->cache_props, list) {
+               cache->kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
+               if (!cache->kobj)
+                       return -ENOMEM;
+               ret = kobject_init_and_add(cache->kobj, &cache_type,
+                               dev->kobj_cache, "%d", i);
+               if (ret < 0)
+                       return ret;
+
+               cache->attr.name = "properties";
+               cache->attr.mode = KFD_SYSFS_FILE_MODE;
+               sysfs_attr_init(&cache->attr);
+               ret = sysfs_create_file(cache->kobj, &cache->attr);
+               if (ret < 0)
+                       return ret;
+               i++;
+       }
+
+       i = 0;
+       list_for_each_entry(iolink, &dev->io_link_props, list) {
+               iolink->kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
+               if (!iolink->kobj)
+                       return -ENOMEM;
+               ret = kobject_init_and_add(iolink->kobj, &iolink_type,
+                               dev->kobj_iolink, "%d", i);
+               if (ret < 0)
+                       return ret;
+
+               iolink->attr.name = "properties";
+               iolink->attr.mode = KFD_SYSFS_FILE_MODE;
+               sysfs_attr_init(&iolink->attr);
+               ret = sysfs_create_file(iolink->kobj, &iolink->attr);
+               if (ret < 0)
+                       return ret;
+               i++;
+}
+
+       return 0;
+}
+
+static int kfd_build_sysfs_node_tree(void)
+{
+       struct kfd_topology_device *dev;
+       int ret;
+       uint32_t i = 0;
+
+       list_for_each_entry(dev, &topology_device_list, list) {
+               ret = kfd_build_sysfs_node_entry(dev, 0);
+               if (ret < 0)
+                       return ret;
+               i++;
+       }
+
+       return 0;
+}
+
+static void kfd_remove_sysfs_node_tree(void)
+{
+       struct kfd_topology_device *dev;
+
+       list_for_each_entry(dev, &topology_device_list, list)
+               kfd_remove_sysfs_node_entry(dev);
+}
+
+static int kfd_topology_update_sysfs(void)
+{
+       int ret;
+
+       pr_info("Creating topology SYSFS entries\n");
+       if (sys_props.kobj_topology == NULL) {
+               sys_props.kobj_topology =
+                               kfd_alloc_struct(sys_props.kobj_topology);
+               if (!sys_props.kobj_topology)
+                       return -ENOMEM;
+
+               ret = kobject_init_and_add(sys_props.kobj_topology,
+                               &sysprops_type,  &kfd_device->kobj,
+                               "topology");
+               if (ret < 0)
+                       return ret;
+
+               sys_props.kobj_nodes = kobject_create_and_add("nodes",
+                               sys_props.kobj_topology);
+               if (!sys_props.kobj_nodes)
+                       return -ENOMEM;
+
+               sys_props.attr_genid.name = "generation_id";
+               sys_props.attr_genid.mode = KFD_SYSFS_FILE_MODE;
+               sysfs_attr_init(&sys_props.attr_genid);
+               ret = sysfs_create_file(sys_props.kobj_topology,
+                               &sys_props.attr_genid);
+               if (ret < 0)
+                       return ret;
+
+               sys_props.attr_props.name = "system_properties";
+               sys_props.attr_props.mode = KFD_SYSFS_FILE_MODE;
+               sysfs_attr_init(&sys_props.attr_props);
+               ret = sysfs_create_file(sys_props.kobj_topology,
+                               &sys_props.attr_props);
+               if (ret < 0)
+                       return ret;
+       }
+
+       kfd_remove_sysfs_node_tree();
+
+       return kfd_build_sysfs_node_tree();
+}
+
+static void kfd_topology_release_sysfs(void)
+{
+       kfd_remove_sysfs_node_tree();
+       if (sys_props.kobj_topology) {
+               sysfs_remove_file(sys_props.kobj_topology,
+                               &sys_props.attr_genid);
+               sysfs_remove_file(sys_props.kobj_topology,
+                               &sys_props.attr_props);
+               if (sys_props.kobj_nodes) {
+                       kobject_del(sys_props.kobj_nodes);
+                       kobject_put(sys_props.kobj_nodes);
+                       sys_props.kobj_nodes = NULL;
+               }
+               kobject_del(sys_props.kobj_topology);
+               kobject_put(sys_props.kobj_topology);
+               sys_props.kobj_topology = NULL;
+       }
+}
+
+int kfd_topology_init(void)
+{
+       void *crat_image = NULL;
+       size_t image_size = 0;
+       int ret;
+
+       /*
+        * Initialize the head for the topology device list
+        */
+       INIT_LIST_HEAD(&topology_device_list);
+       init_rwsem(&topology_lock);
+       topology_crat_parsed = 0;
+
+       memset(&sys_props, 0, sizeof(sys_props));
+
+       /*
+        * Get the CRAT image from the ACPI
+        */
+       ret = kfd_topology_get_crat_acpi(crat_image, &image_size);
+       if (ret == 0 && image_size > 0) {
+               pr_info("Found CRAT image with size=%zd\n", image_size);
+               crat_image = kmalloc(image_size, GFP_KERNEL);
+               if (!crat_image) {
+                       ret = -ENOMEM;
+                       pr_err("No memory for allocating CRAT image\n");
+                       goto err;
+               }
+               ret = kfd_topology_get_crat_acpi(crat_image, &image_size);
+
+               if (ret == 0) {
+                       down_write(&topology_lock);
+                       ret = kfd_parse_crat_table(crat_image);
+                       if (ret == 0)
+                               ret = kfd_topology_update_sysfs();
+                       up_write(&topology_lock);
+               } else {
+                       pr_err("Couldn't get CRAT table size from ACPI\n");
+               }
+               kfree(crat_image);
+       } else if (ret == -ENODATA) {
+               ret = 0;
+       } else {
+               pr_err("Couldn't get CRAT table size from ACPI\n");
+       }
+
+err:
+       pr_info("Finished initializing topology ret=%d\n", ret);
+       return ret;
+}
+
+void kfd_topology_shutdown(void)
+{
+       kfd_topology_release_sysfs();
+       kfd_release_live_view();
+}
+
+static void kfd_debug_print_topology(void)
+{
+       struct kfd_topology_device *dev;
+       uint32_t i = 0;
+
+       pr_info("DEBUG PRINT OF TOPOLOGY:");
+       list_for_each_entry(dev, &topology_device_list, list) {
+               pr_info("Node: %d\n", i);
+               pr_info("\tGPU assigned: %s\n", (dev->gpu ? "yes" : "no"));
+               pr_info("\tCPU count: %d\n", dev->node_props.cpu_cores_count);
+               pr_info("\tSIMD count: %d", dev->node_props.simd_count);
+               i++;
+       }
+}
+
+static uint32_t kfd_generate_gpu_id(struct kfd_dev *gpu)
+{
+       uint32_t hashout;
+       uint32_t buf[7];
+       int i;
+
+       if (!gpu)
+               return 0;
+
+       buf[0] = gpu->pdev->devfn;
+       buf[1] = gpu->pdev->subsystem_vendor;
+       buf[2] = gpu->pdev->subsystem_device;
+       buf[3] = gpu->pdev->device;
+       buf[4] = gpu->pdev->bus->number;
+       buf[5] = (uint32_t)(kfd2kgd->get_vmem_size(gpu->kgd) & 0xffffffff);
+       buf[6] = (uint32_t)(kfd2kgd->get_vmem_size(gpu->kgd) >> 32);
+
+       for (i = 0, hashout = 0; i < 7; i++)
+               hashout ^= hash_32(buf[i], KFD_GPU_ID_HASH_WIDTH);
+
+       return hashout;
+}
+
+static struct kfd_topology_device *kfd_assign_gpu(struct kfd_dev *gpu)
+{
+       struct kfd_topology_device *dev;
+       struct kfd_topology_device *out_dev = NULL;
+
+       BUG_ON(!gpu);
+
+       list_for_each_entry(dev, &topology_device_list, list)
+               if (dev->gpu == NULL && dev->node_props.simd_count > 0) {
+                       dev->gpu = gpu;
+                       out_dev = dev;
+                       break;
+               }
+
+       return out_dev;
+}
+
+static void kfd_notify_gpu_change(uint32_t gpu_id, int arrival)
+{
+       /*
+        * TODO: Generate an event for thunk about the arrival/removal
+        * of the GPU
+        */
+}
+
+int kfd_topology_add_device(struct kfd_dev *gpu)
+{
+       uint32_t gpu_id;
+       struct kfd_topology_device *dev;
+       int res;
+
+       BUG_ON(!gpu);
+
+       gpu_id = kfd_generate_gpu_id(gpu);
+
+       pr_debug("kfd: Adding new GPU (ID: 0x%x) to topology\n", gpu_id);
+
+       down_write(&topology_lock);
+       /*
+        * Try to assign the GPU to existing topology device (generated from
+        * CRAT table
+        */
+       dev = kfd_assign_gpu(gpu);
+       if (!dev) {
+               pr_info("GPU was not found in the current topology. Extending.\n");
+               kfd_debug_print_topology();
+               dev = kfd_create_topology_device();
+               if (!dev) {
+                       res = -ENOMEM;
+                       goto err;
+               }
+               dev->gpu = gpu;
+
+               /*
+                * TODO: Make a call to retrieve topology information from the
+                * GPU vBIOS
+                */
+
+               /*
+                * Update the SYSFS tree, since we added another topology device
+                */
+               if (kfd_topology_update_sysfs() < 0)
+                       kfd_topology_release_sysfs();
+
+       }
+
+       dev->gpu_id = gpu_id;
+       gpu->id = gpu_id;
+       dev->node_props.vendor_id = gpu->pdev->vendor;
+       dev->node_props.device_id = gpu->pdev->device;
+       dev->node_props.location_id = (gpu->pdev->bus->number << 24) +
+                       (gpu->pdev->devfn & 0xffffff);
+       /*
+        * TODO: Retrieve max engine clock values from KGD
+        */
+
+       res = 0;
+
+err:
+       up_write(&topology_lock);
+
+       if (res == 0)
+               kfd_notify_gpu_change(gpu_id, 1);
+
+       return res;
+}
+
+int kfd_topology_remove_device(struct kfd_dev *gpu)
+{
+       struct kfd_topology_device *dev;
+       uint32_t gpu_id;
+       int res = -ENODEV;
+
+       BUG_ON(!gpu);
+
+       down_write(&topology_lock);
+
+       list_for_each_entry(dev, &topology_device_list, list)
+               if (dev->gpu == gpu) {
+                       gpu_id = dev->gpu_id;
+                       kfd_remove_sysfs_node_entry(dev);
+                       kfd_release_topology_device(dev);
+                       res = 0;
+                       if (kfd_topology_update_sysfs() < 0)
+                               kfd_topology_release_sysfs();
+                       break;
+               }
+
+       up_write(&topology_lock);
+
+       if (res == 0)
+               kfd_notify_gpu_change(gpu_id, 0);
+
+       return res;
+}
+
+/*
+ * When idx is out of bounds, the function will return NULL
+ */
+struct kfd_dev *kfd_topology_enum_kfd_devices(uint8_t idx)
+{
+
+       struct kfd_topology_device *top_dev;
+       struct kfd_dev *device = NULL;
+       uint8_t device_idx = 0;
+
+       down_read(&topology_lock);
+
+       list_for_each_entry(top_dev, &topology_device_list, list) {
+               if (device_idx == idx) {
+                       device = top_dev->gpu;
+                       break;
+               }
+
+               device_idx++;
+       }
+
+       up_read(&topology_lock);
+
+       return device;
+
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h
new file mode 100644 (file)
index 0000000..989624b
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __KFD_TOPOLOGY_H__
+#define __KFD_TOPOLOGY_H__
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include "kfd_priv.h"
+
+#define KFD_TOPOLOGY_PUBLIC_NAME_SIZE 128
+
+#define HSA_CAP_HOT_PLUGGABLE                  0x00000001
+#define HSA_CAP_ATS_PRESENT                    0x00000002
+#define HSA_CAP_SHARED_WITH_GRAPHICS           0x00000004
+#define HSA_CAP_QUEUE_SIZE_POW2                        0x00000008
+#define HSA_CAP_QUEUE_SIZE_32BIT               0x00000010
+#define HSA_CAP_QUEUE_IDLE_EVENT               0x00000020
+#define HSA_CAP_VA_LIMIT                       0x00000040
+#define HSA_CAP_WATCH_POINTS_SUPPORTED         0x00000080
+#define HSA_CAP_WATCH_POINTS_TOTALBITS_MASK    0x00000f00
+#define HSA_CAP_WATCH_POINTS_TOTALBITS_SHIFT   8
+#define HSA_CAP_RESERVED                       0xfffff000
+
+struct kfd_node_properties {
+       uint32_t cpu_cores_count;
+       uint32_t simd_count;
+       uint32_t mem_banks_count;
+       uint32_t caches_count;
+       uint32_t io_links_count;
+       uint32_t cpu_core_id_base;
+       uint32_t simd_id_base;
+       uint32_t capability;
+       uint32_t max_waves_per_simd;
+       uint32_t lds_size_in_kb;
+       uint32_t gds_size_in_kb;
+       uint32_t wave_front_size;
+       uint32_t array_count;
+       uint32_t simd_arrays_per_engine;
+       uint32_t cu_per_simd_array;
+       uint32_t simd_per_cu;
+       uint32_t max_slots_scratch_cu;
+       uint32_t engine_id;
+       uint32_t vendor_id;
+       uint32_t device_id;
+       uint32_t location_id;
+       uint32_t max_engine_clk_fcompute;
+       uint32_t max_engine_clk_ccompute;
+       uint16_t marketing_name[KFD_TOPOLOGY_PUBLIC_NAME_SIZE];
+};
+
+#define HSA_MEM_HEAP_TYPE_SYSTEM       0
+#define HSA_MEM_HEAP_TYPE_FB_PUBLIC    1
+#define HSA_MEM_HEAP_TYPE_FB_PRIVATE   2
+#define HSA_MEM_HEAP_TYPE_GPU_GDS      3
+#define HSA_MEM_HEAP_TYPE_GPU_LDS      4
+#define HSA_MEM_HEAP_TYPE_GPU_SCRATCH  5
+
+#define HSA_MEM_FLAGS_HOT_PLUGGABLE    0x00000001
+#define HSA_MEM_FLAGS_NON_VOLATILE     0x00000002
+#define HSA_MEM_FLAGS_RESERVED         0xfffffffc
+
+struct kfd_mem_properties {
+       struct list_head        list;
+       uint32_t                heap_type;
+       uint64_t                size_in_bytes;
+       uint32_t                flags;
+       uint32_t                width;
+       uint32_t                mem_clk_max;
+       struct kobject          *kobj;
+       struct attribute        attr;
+};
+
+#define KFD_TOPOLOGY_CPU_SIBLINGS 256
+
+#define HSA_CACHE_TYPE_DATA            0x00000001
+#define HSA_CACHE_TYPE_INSTRUCTION     0x00000002
+#define HSA_CACHE_TYPE_CPU             0x00000004
+#define HSA_CACHE_TYPE_HSACU           0x00000008
+#define HSA_CACHE_TYPE_RESERVED                0xfffffff0
+
+struct kfd_cache_properties {
+       struct list_head        list;
+       uint32_t                processor_id_low;
+       uint32_t                cache_level;
+       uint32_t                cache_size;
+       uint32_t                cacheline_size;
+       uint32_t                cachelines_per_tag;
+       uint32_t                cache_assoc;
+       uint32_t                cache_latency;
+       uint32_t                cache_type;
+       uint8_t                 sibling_map[KFD_TOPOLOGY_CPU_SIBLINGS];
+       struct kobject          *kobj;
+       struct attribute        attr;
+};
+
+struct kfd_iolink_properties {
+       struct list_head        list;
+       uint32_t                iolink_type;
+       uint32_t                ver_maj;
+       uint32_t                ver_min;
+       uint32_t                node_from;
+       uint32_t                node_to;
+       uint32_t                weight;
+       uint32_t                min_latency;
+       uint32_t                max_latency;
+       uint32_t                min_bandwidth;
+       uint32_t                max_bandwidth;
+       uint32_t                rec_transfer_size;
+       uint32_t                flags;
+       struct kobject          *kobj;
+       struct attribute        attr;
+};
+
+struct kfd_topology_device {
+       struct list_head                list;
+       uint32_t                        gpu_id;
+       struct kfd_node_properties      node_props;
+       uint32_t                        mem_bank_count;
+       struct list_head                mem_props;
+       uint32_t                        cache_count;
+       struct list_head                cache_props;
+       uint32_t                        io_link_count;
+       struct list_head                io_link_props;
+       struct kfd_dev                  *gpu;
+       struct kobject                  *kobj_node;
+       struct kobject                  *kobj_mem;
+       struct kobject                  *kobj_cache;
+       struct kobject                  *kobj_iolink;
+       struct attribute                attr_gpuid;
+       struct attribute                attr_name;
+       struct attribute                attr_props;
+};
+
+struct kfd_system_properties {
+       uint32_t                num_devices;     /* Number of H-NUMA nodes */
+       uint32_t                generation_count;
+       uint64_t                platform_oem;
+       uint64_t                platform_id;
+       uint64_t                platform_rev;
+       struct kobject          *kobj_topology;
+       struct kobject          *kobj_nodes;
+       struct attribute        attr_genid;
+       struct attribute        attr_props;
+};
+
+
+
+#endif /* __KFD_TOPOLOGY_H__ */
diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
new file mode 100644 (file)
index 0000000..9c729dd
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * This file defines the private interface between the
+ * AMD kernel graphics drivers and the AMD KFD.
+ */
+
+#ifndef KGD_KFD_INTERFACE_H_INCLUDED
+#define KGD_KFD_INTERFACE_H_INCLUDED
+
+#include <linux/types.h>
+
+struct pci_dev;
+
+#define KFD_INTERFACE_VERSION 1
+
+struct kfd_dev;
+struct kgd_dev;
+
+struct kgd_mem;
+
+enum kgd_memory_pool {
+       KGD_POOL_SYSTEM_CACHEABLE = 1,
+       KGD_POOL_SYSTEM_WRITECOMBINE = 2,
+       KGD_POOL_FRAMEBUFFER = 3,
+};
+
+struct kgd2kfd_shared_resources {
+       /* Bit n == 1 means VMID n is available for KFD. */
+       unsigned int compute_vmid_bitmap;
+
+       /* Compute pipes are counted starting from MEC0/pipe0 as 0. */
+       unsigned int first_compute_pipe;
+
+       /* Number of MEC pipes available for KFD. */
+       unsigned int compute_pipe_count;
+
+       /* Base address of doorbell aperture. */
+       phys_addr_t doorbell_physical_address;
+
+       /* Size in bytes of doorbell aperture. */
+       size_t doorbell_aperture_size;
+
+       /* Number of bytes at start of aperture reserved for KGD. */
+       size_t doorbell_start_offset;
+};
+
+/**
+ * struct kgd2kfd_calls
+ *
+ * @exit: Notifies amdkfd that kgd module is unloaded
+ *
+ * @probe: Notifies amdkfd about a probe done on a device in the kgd driver.
+ *
+ * @device_init: Initialize the newly probed device (if it is a device that
+ * amdkfd supports)
+ *
+ * @device_exit: Notifies amdkfd about a removal of a kgd device
+ *
+ * @suspend: Notifies amdkfd about a suspend action done to a kgd device
+ *
+ * @resume: Notifies amdkfd about a resume action done to a kgd device
+ *
+ * This structure contains function callback pointers so the kgd driver
+ * will notify to the amdkfd about certain status changes.
+ *
+ */
+struct kgd2kfd_calls {
+       void (*exit)(void);
+       struct kfd_dev* (*probe)(struct kgd_dev *kgd, struct pci_dev *pdev);
+       bool (*device_init)(struct kfd_dev *kfd,
+                       const struct kgd2kfd_shared_resources *gpu_resources);
+       void (*device_exit)(struct kfd_dev *kfd);
+       void (*interrupt)(struct kfd_dev *kfd, const void *ih_ring_entry);
+       void (*suspend)(struct kfd_dev *kfd);
+       int (*resume)(struct kfd_dev *kfd);
+};
+
+/**
+ * struct kfd2kgd_calls
+ *
+ * @init_sa_manager: Initialize an instance of the sa manager, used by
+ * amdkfd for all system memory allocations that are mapped to the GART
+ * address space
+ *
+ * @fini_sa_manager: Releases all memory allocations for amdkfd that are
+ * handled by kgd sa manager
+ *
+ * @allocate_mem: Allocate a buffer from amdkfd's sa manager. The buffer can
+ * be used for mqds, hpds, kernel queue, fence and runlists
+ *
+ * @free_mem: Frees a buffer that was allocated by amdkfd's sa manager
+ *
+ * @get_vmem_size: Retrieves (physical) size of VRAM
+ *
+ * @get_gpu_clock_counter: Retrieves GPU clock counter
+ *
+ * @get_max_engine_clock_in_mhz: Retrieves maximum GPU clock in MHz
+ *
+ * @program_sh_mem_settings: A function that should initiate the memory
+ * properties such as main aperture memory type (cache / non cached) and
+ * secondary aperture base address, size and memory type.
+ * This function is used only for no cp scheduling mode.
+ *
+ * @set_pasid_vmid_mapping: Exposes pasid/vmid pair to the H/W for no cp
+ * scheduling mode. Only used for no cp scheduling mode.
+ *
+ * @init_memory: Initializes memory apertures to fixed base/limit address
+ * and non cached memory types.
+ *
+ * @init_pipeline: Initialized the compute pipelines.
+ *
+ * @hqd_load: Loads the mqd structure to a H/W hqd slot. used only for no cp
+ * sceduling mode.
+ *
+ * @hqd_is_occupies: Checks if a hqd slot is occupied.
+ *
+ * @hqd_destroy: Destructs and preempts the queue assigned to that hqd slot.
+ *
+ * This structure contains function pointers to services that the kgd driver
+ * provides to amdkfd driver.
+ *
+ */
+struct kfd2kgd_calls {
+       /* Memory management. */
+       int (*init_sa_manager)(struct kgd_dev *kgd, unsigned int size);
+       void (*fini_sa_manager)(struct kgd_dev *kgd);
+       int (*allocate_mem)(struct kgd_dev *kgd, size_t size, size_t alignment,
+                       enum kgd_memory_pool pool, struct kgd_mem **mem);
+
+       void (*free_mem)(struct kgd_dev *kgd, struct kgd_mem *mem);
+
+       uint64_t (*get_vmem_size)(struct kgd_dev *kgd);
+       uint64_t (*get_gpu_clock_counter)(struct kgd_dev *kgd);
+
+       uint32_t (*get_max_engine_clock_in_mhz)(struct kgd_dev *kgd);
+
+       /* Register access functions */
+       void (*program_sh_mem_settings)(struct kgd_dev *kgd, uint32_t vmid,
+                       uint32_t sh_mem_config, uint32_t sh_mem_ape1_base,
+                       uint32_t sh_mem_ape1_limit, uint32_t sh_mem_bases);
+
+       int (*set_pasid_vmid_mapping)(struct kgd_dev *kgd, unsigned int pasid,
+                                       unsigned int vmid);
+
+       int (*init_memory)(struct kgd_dev *kgd);
+       int (*init_pipeline)(struct kgd_dev *kgd, uint32_t pipe_id,
+                               uint32_t hpd_size, uint64_t hpd_gpu_addr);
+
+       int (*hqd_load)(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
+                       uint32_t queue_id, uint32_t __user *wptr);
+
+       bool (*hqd_is_occupies)(struct kgd_dev *kgd, uint64_t queue_address,
+                               uint32_t pipe_id, uint32_t queue_id);
+
+       int (*hqd_destroy)(struct kgd_dev *kgd, uint32_t reset_type,
+                               unsigned int timeout, uint32_t pipe_id,
+                               uint32_t queue_id);
+};
+
+bool kgd2kfd_init(unsigned interface_version,
+                 const struct kfd2kgd_calls *f2g,
+                 const struct kgd2kfd_calls **g2f);
+
+#endif /* KGD_KFD_INTERFACE_H_INCLUDED */
index fe95d31cd1101118ab8be6174621fbd4692526f9..61dbf09dff5dca3549460039322406eb73fb7bf7 100644 (file)
@@ -9,6 +9,17 @@
 
 /* ---------------------------------------------------------------------- */
 
+static int bochsfb_mmap(struct fb_info *info,
+                       struct vm_area_struct *vma)
+{
+       struct drm_fb_helper *fb_helper = info->par;
+       struct bochs_device *bochs =
+               container_of(fb_helper, struct bochs_device, fb.helper);
+       struct bochs_bo *bo = gem_to_bochs_bo(bochs->fb.gfb.obj);
+
+       return ttm_fbdev_mmap(vma, &bo->bo);
+}
+
 static struct fb_ops bochsfb_ops = {
        .owner = THIS_MODULE,
        .fb_check_var = drm_fb_helper_check_var,
@@ -19,6 +30,7 @@ static struct fb_ops bochsfb_ops = {
        .fb_pan_display = drm_fb_helper_pan_display,
        .fb_blank = drm_fb_helper_blank,
        .fb_setcmap = drm_fb_helper_setcmap,
+       .fb_mmap = bochsfb_mmap,
 };
 
 static int bochsfb_create_object(struct bochs_device *bochs,
@@ -123,11 +135,9 @@ static int bochsfb_create(struct drm_fb_helper *helper,
        info->screen_base = bo->kmap.virtual;
        info->screen_size = size;
 
-#if 0
-       /* FIXME: get this right for mmap(/dev/fb0) */
-       info->fix.smem_start = bochs_bo_mmap_offset(bo);
+       drm_vma_offset_remove(&bo->bo.bdev->vma_manager, &bo->bo.vma_node);
+       info->fix.smem_start = 0;
        info->fix.smem_len = size;
-#endif
 
        ret = fb_alloc_cmap(&info->cmap, 256, 0);
        if (ret) {
index dbe619e6aab4e28e2c5d58b8ee87f1bb91b7eb5c..460389702d31cdca34a56b9e20c93f6ad4ad6f05 100644 (file)
@@ -51,11 +51,10 @@ int bochs_hw_init(struct drm_device *dev, uint32_t flags)
 {
        struct bochs_device *bochs = dev->dev_private;
        struct pci_dev *pdev = dev->pdev;
-       unsigned long addr, size, mem, ioaddr, iosize;
+       unsigned long addr, size, mem, ioaddr, iosize, qext_size;
        u16 id;
 
-       if (/* (ent->driver_data == BOCHS_QEMU_STDVGA) && */
-           (pdev->resource[2].flags & IORESOURCE_MEM)) {
+       if (pdev->resource[2].flags & IORESOURCE_MEM) {
                /* mmio bar with vga and bochs registers present */
                if (pci_request_region(pdev, 2, "bochs-drm") != 0) {
                        DRM_ERROR("Cannot request mmio region\n");
@@ -116,6 +115,24 @@ int bochs_hw_init(struct drm_device *dev, uint32_t flags)
                 size / 1024, addr,
                 bochs->ioports ? "ioports" : "mmio",
                 ioaddr);
+
+       if (bochs->mmio && pdev->revision >= 2) {
+               qext_size = readl(bochs->mmio + 0x600);
+               if (qext_size < 4 || qext_size > iosize)
+                       goto noext;
+               DRM_DEBUG("Found qemu ext regs, size %ld\n", qext_size);
+               if (qext_size >= 8) {
+#ifdef __BIG_ENDIAN
+                       writel(0xbebebebe, bochs->mmio + 0x604);
+#else
+                       writel(0x1e1e1e1e, bochs->mmio + 0x604);
+#endif
+                       DRM_DEBUG("  qext endian: 0x%x\n",
+                                 readl(bochs->mmio + 0x604));
+               }
+       }
+
+noext:
        return 0;
 }
 
index 5ffd4895d040a08a911a129699a2c4c5fbbe5915..85f0f8cf1fb82974f14f5491acaca9dae02cfeb0 100644 (file)
@@ -109,11 +109,32 @@ static void bochs_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
 {
 }
 
+static int bochs_crtc_page_flip(struct drm_crtc *crtc,
+                               struct drm_framebuffer *fb,
+                               struct drm_pending_vblank_event *event,
+                               uint32_t page_flip_flags)
+{
+       struct bochs_device *bochs =
+               container_of(crtc, struct bochs_device, crtc);
+       struct drm_framebuffer *old_fb = crtc->primary->fb;
+       unsigned long irqflags;
+
+       crtc->primary->fb = fb;
+       bochs_crtc_mode_set_base(crtc, 0, 0, old_fb);
+       if (event) {
+               spin_lock_irqsave(&bochs->dev->event_lock, irqflags);
+               drm_send_vblank_event(bochs->dev, -1, event);
+               spin_unlock_irqrestore(&bochs->dev->event_lock, irqflags);
+       }
+       return 0;
+}
+
 /* These provide the minimum set of functions required to handle a CRTC */
 static const struct drm_crtc_funcs bochs_crtc_funcs = {
        .gamma_set = bochs_crtc_gamma_set,
        .set_config = drm_crtc_helper_set_config,
        .destroy = drm_crtc_cleanup,
+       .page_flip = bochs_crtc_page_flip,
 };
 
 static const struct drm_crtc_helper_funcs bochs_helper_funcs = {
index d44e69daa23966c0e2f38332069a81cc24070d0a..693a4565c4ffb2a0629d48ec206ba3bb4accf830 100644 (file)
@@ -210,6 +210,9 @@ int cirrus_framebuffer_init(struct drm_device *dev,
                            struct drm_mode_fb_cmd2 *mode_cmd,
                            struct drm_gem_object *obj);
 
+bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height,
+                             int bpp, int pitch);
+
                                /* cirrus_display.c */
 int cirrus_modeset_init(struct cirrus_device *cdev);
 void cirrus_modeset_fini(struct cirrus_device *cdev);
index d231b1c317afac94476e572b9560566311a38168..502a89eb54b51a7f146e9e61e54f03a0051c9b2d 100644 (file)
@@ -139,6 +139,7 @@ static int cirrusfb_create_object(struct cirrus_fbdev *afbdev,
                               struct drm_gem_object **gobj_p)
 {
        struct drm_device *dev = afbdev->helper.dev;
+       struct cirrus_device *cdev = dev->dev_private;
        u32 bpp, depth;
        u32 size;
        struct drm_gem_object *gobj;
@@ -146,8 +147,10 @@ static int cirrusfb_create_object(struct cirrus_fbdev *afbdev,
        int ret = 0;
        drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp);
 
-       if (bpp > 24)
+       if (!cirrus_check_framebuffer(cdev, mode_cmd->width, mode_cmd->height,
+                                     bpp, mode_cmd->pitches[0]))
                return -EINVAL;
+
        size = mode_cmd->pitches[0] * mode_cmd->height;
        ret = cirrus_gem_create(dev, size, true, &gobj);
        if (ret)
index 99c1983f99d228b77ce9c498236ad68b348440e2..4c2d68e9102d6304b8fd5cc655266300706f32da 100644 (file)
@@ -49,14 +49,16 @@ cirrus_user_framebuffer_create(struct drm_device *dev,
                               struct drm_file *filp,
                               struct drm_mode_fb_cmd2 *mode_cmd)
 {
+       struct cirrus_device *cdev = dev->dev_private;
        struct drm_gem_object *obj;
        struct cirrus_framebuffer *cirrus_fb;
        int ret;
        u32 bpp, depth;
 
        drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp);
-       /* cirrus can't handle > 24bpp framebuffers at all */
-       if (bpp > 24)
+
+       if (!cirrus_check_framebuffer(cdev, mode_cmd->width, mode_cmd->height,
+                                     bpp, mode_cmd->pitches[0]))
                return ERR_PTR(-EINVAL);
 
        obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]);
@@ -96,8 +98,7 @@ static int cirrus_vram_init(struct cirrus_device *cdev)
 {
        /* BAR 0 is VRAM */
        cdev->mc.vram_base = pci_resource_start(cdev->dev->pdev, 0);
-       /* We have 4MB of VRAM */
-       cdev->mc.vram_size = 4 * 1024 * 1024;
+       cdev->mc.vram_size = pci_resource_len(cdev->dev->pdev, 0);
 
        if (!request_mem_region(cdev->mc.vram_base, cdev->mc.vram_size,
                                "cirrusdrmfb_vram")) {
@@ -179,17 +180,22 @@ int cirrus_driver_load(struct drm_device *dev, unsigned long flags)
        }
 
        r = cirrus_mm_init(cdev);
-       if (r)
+       if (r) {
                dev_err(&dev->pdev->dev, "fatal err on mm init\n");
+               goto out;
+       }
 
        r = cirrus_modeset_init(cdev);
-       if (r)
+       if (r) {
                dev_err(&dev->pdev->dev, "Fatal error during modeset init: %d\n", r);
+               goto out;
+       }
 
        dev->mode_config.funcs = (void *)&cirrus_mode_funcs;
+
+       return 0;
 out:
-       if (r)
-               cirrus_driver_unload(dev);
+       cirrus_driver_unload(dev);
        return r;
 }
 
@@ -307,3 +313,21 @@ out_unlock:
        return ret;
 
 }
+
+bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height,
+                             int bpp, int pitch)
+{
+       const int max_pitch = 0x1FF << 3; /* (4096 - 1) & ~111b bytes */
+       const int max_size = cdev->mc.vram_size;
+
+       if (bpp > 32)
+               return false;
+
+       if (pitch > max_pitch)
+               return false;
+
+       if (pitch * height > max_size)
+               return false;
+
+       return true;
+}
index ed991ba66e21932c66ff828334dfba1bb343865a..ff5f034cc40526ba4504d725d06228c662232417 100644 (file)
@@ -56,6 +56,8 @@ drm_atomic_state_alloc(struct drm_device *dev)
        if (!state)
                return NULL;
 
+       state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector);
+
        state->crtcs = kcalloc(dev->mode_config.num_crtc,
                               sizeof(*state->crtcs), GFP_KERNEL);
        if (!state->crtcs)
@@ -72,12 +74,12 @@ drm_atomic_state_alloc(struct drm_device *dev)
                                      sizeof(*state->plane_states), GFP_KERNEL);
        if (!state->plane_states)
                goto fail;
-       state->connectors = kcalloc(dev->mode_config.num_connector,
+       state->connectors = kcalloc(state->num_connector,
                                    sizeof(*state->connectors),
                                    GFP_KERNEL);
        if (!state->connectors)
                goto fail;
-       state->connector_states = kcalloc(dev->mode_config.num_connector,
+       state->connector_states = kcalloc(state->num_connector,
                                          sizeof(*state->connector_states),
                                          GFP_KERNEL);
        if (!state->connector_states)
@@ -112,21 +114,24 @@ EXPORT_SYMBOL(drm_atomic_state_alloc);
 void drm_atomic_state_clear(struct drm_atomic_state *state)
 {
        struct drm_device *dev = state->dev;
+       struct drm_mode_config *config = &dev->mode_config;
        int i;
 
        DRM_DEBUG_KMS("Clearing atomic state %p\n", state);
 
-       for (i = 0; i < dev->mode_config.num_connector; i++) {
+       for (i = 0; i < state->num_connector; i++) {
                struct drm_connector *connector = state->connectors[i];
 
                if (!connector)
                        continue;
 
+               WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
+
                connector->funcs->atomic_destroy_state(connector,
                                                       state->connector_states[i]);
        }
 
-       for (i = 0; i < dev->mode_config.num_crtc; i++) {
+       for (i = 0; i < config->num_crtc; i++) {
                struct drm_crtc *crtc = state->crtcs[i];
 
                if (!crtc)
@@ -136,7 +141,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
                                                  state->crtc_states[i]);
        }
 
-       for (i = 0; i < dev->mode_config.num_total_plane; i++) {
+       for (i = 0; i < config->num_total_plane; i++) {
                struct drm_plane *plane = state->planes[i];
 
                if (!plane)
@@ -238,13 +243,7 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
        if (state->plane_states[index])
                return state->plane_states[index];
 
-       /*
-        * TODO: We currently don't have per-plane mutexes. So instead of trying
-        * crazy tricks with deferring plane->crtc and hoping for the best just
-        * grab all crtc locks. Once we have per-plane locks we must update this
-        * to only take the plane mutex.
-        */
-       ret = drm_modeset_lock_all_crtcs(state->dev, state->acquire_ctx);
+       ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx);
        if (ret)
                return ERR_PTR(ret);
 
@@ -295,15 +294,30 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
        struct drm_mode_config *config = &connector->dev->mode_config;
        struct drm_connector_state *connector_state;
 
+       ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
+       if (ret)
+               return ERR_PTR(ret);
+
        index = drm_connector_index(connector);
 
+       /*
+        * Construction of atomic state updates can race with a connector
+        * hot-add which might overflow. In this case flip the table and just
+        * restart the entire ioctl - no one is fast enough to livelock a cpu
+        * with physical hotplug events anyway.
+        *
+        * Note that we only grab the indexes once we have the right lock to
+        * prevent hotplug/unplugging of connectors. So removal is no problem,
+        * at most the array is a bit too large.
+        */
+       if (index >= state->num_connector) {
+               DRM_DEBUG_KMS("Hot-added connector would overflow state array, restarting\n");
+               return ERR_PTR(-EAGAIN);
+       }
+
        if (state->connector_states[index])
                return state->connector_states[index];
 
-       ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
-       if (ret)
-               return ERR_PTR(ret);
-
        connector_state = connector->funcs->atomic_duplicate_state(connector);
        if (!connector_state)
                return ERR_PTR(-ENOMEM);
@@ -330,7 +344,8 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state);
 
 /**
  * drm_atomic_set_crtc_for_plane - set crtc for plane
- * @plane_state: atomic state object for the plane
+ * @state: the incoming atomic state
+ * @plane: the plane whose incoming state to update
  * @crtc: crtc to use for the plane
  *
  * Changing the assigned crtc for a plane requires us to grab the lock and state
@@ -343,20 +358,35 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state);
  * sequence must be restarted. All other errors are fatal.
  */
 int
-drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
-                             struct drm_crtc *crtc)
+drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state,
+                             struct drm_plane *plane, struct drm_crtc *crtc)
 {
+       struct drm_plane_state *plane_state =
+                       drm_atomic_get_plane_state(state, plane);
        struct drm_crtc_state *crtc_state;
 
+       if (WARN_ON(IS_ERR(plane_state)))
+               return PTR_ERR(plane_state);
+
+       if (plane_state->crtc) {
+               crtc_state = drm_atomic_get_crtc_state(plane_state->state,
+                                                      plane_state->crtc);
+               if (WARN_ON(IS_ERR(crtc_state)))
+                       return PTR_ERR(crtc_state);
+
+               crtc_state->plane_mask &= ~(1 << drm_plane_index(plane));
+       }
+
+       plane_state->crtc = crtc;
+
        if (crtc) {
                crtc_state = drm_atomic_get_crtc_state(plane_state->state,
                                                       crtc);
                if (IS_ERR(crtc_state))
                        return PTR_ERR(crtc_state);
+               crtc_state->plane_mask |= (1 << drm_plane_index(plane));
        }
 
-       plane_state->crtc = crtc;
-
        if (crtc)
                DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n",
                              plane_state, crtc->base.id);
@@ -496,10 +526,9 @@ int
 drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
                               struct drm_crtc *crtc)
 {
-       int nconnectors = state->dev->mode_config.num_connector;
        int i, num_connected_connectors = 0;
 
-       for (i = 0; i < nconnectors; i++) {
+       for (i = 0; i < state->num_connector; i++) {
                struct drm_connector_state *conn_state;
 
                conn_state = state->connector_states[i];
index ca839bd9bb0d2f398ca4d7e5ebbb6491b614cba4..4a78a773151ce71f464d36cc4d1d6d887eea1619 100644 (file)
@@ -249,7 +249,6 @@ static int
 mode_fixup(struct drm_atomic_state *state)
 {
        int ncrtcs = state->dev->mode_config.num_crtc;
-       int nconnectors = state->dev->mode_config.num_connector;
        struct drm_crtc_state *crtc_state;
        struct drm_connector_state *conn_state;
        int i;
@@ -264,7 +263,7 @@ mode_fixup(struct drm_atomic_state *state)
                drm_mode_copy(&crtc_state->adjusted_mode, &crtc_state->mode);
        }
 
-       for (i = 0; i < nconnectors; i++) {
+       for (i = 0; i < state->num_connector; i++) {
                struct drm_encoder_helper_funcs *funcs;
                struct drm_encoder *encoder;
 
@@ -332,11 +331,10 @@ mode_fixup(struct drm_atomic_state *state)
 }
 
 static int
-drm_atomic_helper_check_prepare(struct drm_device *dev,
+drm_atomic_helper_check_modeset(struct drm_device *dev,
                                struct drm_atomic_state *state)
 {
        int ncrtcs = dev->mode_config.num_crtc;
-       int nconnectors = dev->mode_config.num_connector;
        struct drm_crtc *crtc;
        struct drm_crtc_state *crtc_state;
        int i, ret;
@@ -361,7 +359,7 @@ drm_atomic_helper_check_prepare(struct drm_device *dev,
                }
        }
 
-       for (i = 0; i < nconnectors; i++) {
+       for (i = 0; i < state->num_connector; i++) {
                /*
                 * This only sets crtc->mode_changed for routing changes,
                 * drivers must set crtc->mode_changed themselves when connector
@@ -430,10 +428,6 @@ int drm_atomic_helper_check(struct drm_device *dev,
        int ncrtcs = dev->mode_config.num_crtc;
        int i, ret = 0;
 
-       ret = drm_atomic_helper_check_prepare(dev, state);
-       if (ret)
-               return ret;
-
        for (i = 0; i < nplanes; i++) {
                struct drm_plane_helper_funcs *funcs;
                struct drm_plane *plane = state->planes[i];
@@ -477,6 +471,10 @@ int drm_atomic_helper_check(struct drm_device *dev,
                }
        }
 
+       ret = drm_atomic_helper_check_modeset(dev, state);
+       if (ret)
+               return ret;
+
        return ret;
 }
 EXPORT_SYMBOL(drm_atomic_helper_check);
@@ -485,10 +483,9 @@ static void
 disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 {
        int ncrtcs = old_state->dev->mode_config.num_crtc;
-       int nconnectors = old_state->dev->mode_config.num_connector;
        int i;
 
-       for (i = 0; i < nconnectors; i++) {
+       for (i = 0; i < old_state->num_connector; i++) {
                struct drm_connector_state *old_conn_state;
                struct drm_connector *connector;
                struct drm_encoder_helper_funcs *funcs;
@@ -502,9 +499,12 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
                if (!old_conn_state || !old_conn_state->crtc)
                        continue;
 
-               encoder = connector->state->best_encoder;
+               encoder = old_conn_state->best_encoder;
 
-               if (!encoder)
+               /* We shouldn't get this far if we didn't previously have
+                * an encoder.. but WARN_ON() rather than explode.
+                */
+               if (WARN_ON(!encoder))
                        continue;
 
                funcs = encoder->helper_private;
@@ -553,12 +553,11 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 static void
 set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state)
 {
-       int nconnectors = dev->mode_config.num_connector;
        int ncrtcs = old_state->dev->mode_config.num_crtc;
        int i;
 
        /* clear out existing links */
-       for (i = 0; i < nconnectors; i++) {
+       for (i = 0; i < old_state->num_connector; i++) {
                struct drm_connector *connector;
 
                connector = old_state->connectors[i];
@@ -573,7 +572,7 @@ set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state)
        }
 
        /* set new links */
-       for (i = 0; i < nconnectors; i++) {
+       for (i = 0; i < old_state->num_connector; i++) {
                struct drm_connector *connector;
 
                connector = old_state->connectors[i];
@@ -608,7 +607,6 @@ static void
 crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
 {
        int ncrtcs = old_state->dev->mode_config.num_crtc;
-       int nconnectors = old_state->dev->mode_config.num_connector;
        int i;
 
        for (i = 0; i < ncrtcs; i++) {
@@ -626,7 +624,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
                        funcs->mode_set_nofb(crtc);
        }
 
-       for (i = 0; i < nconnectors; i++) {
+       for (i = 0; i < old_state->num_connector; i++) {
                struct drm_connector *connector;
                struct drm_crtc_state *new_crtc_state;
                struct drm_encoder_helper_funcs *funcs;
@@ -687,7 +685,6 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
                                          struct drm_atomic_state *old_state)
 {
        int ncrtcs = old_state->dev->mode_config.num_crtc;
-       int nconnectors = old_state->dev->mode_config.num_connector;
        int i;
 
        for (i = 0; i < ncrtcs; i++) {
@@ -706,7 +703,7 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
                        funcs->commit(crtc);
        }
 
-       for (i = 0; i < nconnectors; i++) {
+       for (i = 0; i < old_state->num_connector; i++) {
                struct drm_connector *connector;
                struct drm_encoder_helper_funcs *funcs;
                struct drm_encoder *encoder;
@@ -754,8 +751,47 @@ static void wait_for_fences(struct drm_device *dev,
        }
 }
 
-static void
-wait_for_vblanks(struct drm_device *dev, struct drm_atomic_state *old_state)
+static bool framebuffer_changed(struct drm_device *dev,
+                               struct drm_atomic_state *old_state,
+                               struct drm_crtc *crtc)
+{
+       struct drm_plane *plane;
+       struct drm_plane_state *old_plane_state;
+       int nplanes = old_state->dev->mode_config.num_total_plane;
+       int i;
+
+       for (i = 0; i < nplanes; i++) {
+               plane = old_state->planes[i];
+               old_plane_state = old_state->plane_states[i];
+
+               if (!plane)
+                       continue;
+
+               if (plane->state->crtc != crtc &&
+                   old_plane_state->crtc != crtc)
+                       continue;
+
+               if (plane->state->fb != old_plane_state->fb)
+                       return true;
+       }
+
+       return false;
+}
+
+/**
+ * drm_atomic_helper_wait_for_vblanks - wait for vblank on crtcs
+ * @dev: DRM device
+ * @old_state: atomic state object with old state structures
+ *
+ * Helper to, after atomic commit, wait for vblanks on all effected
+ * crtcs (ie. before cleaning up old framebuffers using
+ * drm_atomic_helper_cleanup_planes()). It will only wait on crtcs where the
+ * framebuffers have actually changed to optimize for the legacy cursor and
+ * plane update use-case.
+ */
+void
+drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
+               struct drm_atomic_state *old_state)
 {
        struct drm_crtc *crtc;
        struct drm_crtc_state *old_crtc_state;
@@ -777,6 +813,9 @@ wait_for_vblanks(struct drm_device *dev, struct drm_atomic_state *old_state)
                if (!crtc->state->enable)
                        continue;
 
+               if (!framebuffer_changed(dev, old_state, crtc))
+                       continue;
+
                ret = drm_crtc_vblank_get(crtc);
                if (ret != 0)
                        continue;
@@ -800,6 +839,7 @@ wait_for_vblanks(struct drm_device *dev, struct drm_atomic_state *old_state)
                drm_crtc_vblank_put(crtc);
        }
 }
+EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks);
 
 /**
  * drm_atomic_helper_commit - commit validated state object
@@ -859,7 +899,7 @@ int drm_atomic_helper_commit(struct drm_device *dev,
 
        drm_atomic_helper_commit_post_planes(dev, state);
 
-       wait_for_vblanks(dev, state);
+       drm_atomic_helper_wait_for_vblanks(dev, state);
 
        drm_atomic_helper_cleanup_planes(dev, state);
 
@@ -971,18 +1011,18 @@ EXPORT_SYMBOL(drm_atomic_helper_prepare_planes);
 /**
  * drm_atomic_helper_commit_planes - commit plane state
  * @dev: DRM device
- * @state: atomic state
+ * @old_state: atomic state object with old state structures
  *
  * This function commits the new plane state using the plane and atomic helper
  * functions for planes and crtcs. It assumes that the atomic state has already
  * been pushed into the relevant object state pointers, since this step can no
  * longer fail.
  *
- * It still requires the global state object @state to know which planes and
+ * It still requires the global state object @old_state to know which planes and
  * crtcs need to be updated though.
  */
 void drm_atomic_helper_commit_planes(struct drm_device *dev,
-                                    struct drm_atomic_state *state)
+                                    struct drm_atomic_state *old_state)
 {
        int nplanes = dev->mode_config.num_total_plane;
        int ncrtcs = dev->mode_config.num_crtc;
@@ -990,7 +1030,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
 
        for (i = 0; i < ncrtcs; i++) {
                struct drm_crtc_helper_funcs *funcs;
-               struct drm_crtc *crtc = state->crtcs[i];
+               struct drm_crtc *crtc = old_state->crtcs[i];
 
                if (!crtc)
                        continue;
@@ -1005,7 +1045,8 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
 
        for (i = 0; i < nplanes; i++) {
                struct drm_plane_helper_funcs *funcs;
-               struct drm_plane *plane = state->planes[i];
+               struct drm_plane *plane = old_state->planes[i];
+               struct drm_plane_state *old_plane_state;
 
                if (!plane)
                        continue;
@@ -1015,12 +1056,14 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
                if (!funcs || !funcs->atomic_update)
                        continue;
 
-               funcs->atomic_update(plane);
+               old_plane_state = old_state->plane_states[i];
+
+               funcs->atomic_update(plane, old_plane_state);
        }
 
        for (i = 0; i < ncrtcs; i++) {
                struct drm_crtc_helper_funcs *funcs;
-               struct drm_crtc *crtc = state->crtcs[i];
+               struct drm_crtc *crtc = old_state->crtcs[i];
 
                if (!crtc)
                        continue;
@@ -1179,7 +1222,7 @@ retry:
                goto fail;
        }
 
-       ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
+       ret = drm_atomic_set_crtc_for_plane(state, plane, crtc);
        if (ret != 0)
                goto fail;
        drm_atomic_set_fb_for_plane(plane_state, fb);
@@ -1206,8 +1249,8 @@ fail:
 
        return ret;
 backoff:
-       drm_atomic_legacy_backoff(state);
        drm_atomic_state_clear(state);
+       drm_atomic_legacy_backoff(state);
 
        /*
         * Someone might have exchanged the framebuffer while we dropped locks
@@ -1235,6 +1278,17 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane)
        struct drm_plane_state *plane_state;
        int ret = 0;
 
+       /*
+        * FIXME: Without plane->crtc set we can't get at the implicit legacy
+        * acquire context. The real fix will be to wire the acquire ctx through
+        * everywhere we need it, but meanwhile prevent chaos by just skipping
+        * this noop. The critical case is the cursor ioctls which a) only grab
+        * crtc/cursor-plane locks (so we need the crtc to get at the right
+        * acquire context) and b) can try to disable the plane multiple times.
+        */
+       if (!plane->crtc)
+               return 0;
+
        state = drm_atomic_state_alloc(plane->dev);
        if (!state)
                return -ENOMEM;
@@ -1247,7 +1301,7 @@ retry:
                goto fail;
        }
 
-       ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
+       ret = drm_atomic_set_crtc_for_plane(state, plane, NULL);
        if (ret != 0)
                goto fail;
        drm_atomic_set_fb_for_plane(plane_state, NULL);
@@ -1274,8 +1328,8 @@ fail:
 
        return ret;
 backoff:
-       drm_atomic_legacy_backoff(state);
        drm_atomic_state_clear(state);
+       drm_atomic_legacy_backoff(state);
 
        /*
         * Someone might have exchanged the framebuffer while we dropped locks
@@ -1293,7 +1347,6 @@ static int update_output_state(struct drm_atomic_state *state,
 {
        struct drm_device *dev = set->crtc->dev;
        struct drm_connector_state *conn_state;
-       int nconnectors = state->dev->mode_config.num_connector;
        int ncrtcs = state->dev->mode_config.num_crtc;
        int ret, i, j;
 
@@ -1322,7 +1375,7 @@ static int update_output_state(struct drm_atomic_state *state,
        }
 
        /* Then recompute connector->crtc links and crtc enabling state. */
-       for (i = 0; i < nconnectors; i++) {
+       for (i = 0; i < state->num_connector; i++) {
                struct drm_connector *connector;
 
                connector = state->connectors[i];
@@ -1399,11 +1452,24 @@ retry:
                goto fail;
        }
 
+       primary_state = drm_atomic_get_plane_state(state, crtc->primary);
+       if (IS_ERR(primary_state)) {
+               ret = PTR_ERR(primary_state);
+               goto fail;
+       }
+
        if (!set->mode) {
                WARN_ON(set->fb);
                WARN_ON(set->num_connectors);
 
                crtc_state->enable = false;
+
+               ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, NULL);
+               if (ret != 0)
+                       goto fail;
+
+               drm_atomic_set_fb_for_plane(primary_state, NULL);
+
                goto commit;
        }
 
@@ -1413,13 +1479,7 @@ retry:
        crtc_state->enable = true;
        drm_mode_copy(&crtc_state->mode, set->mode);
 
-       primary_state = drm_atomic_get_plane_state(state, crtc->primary);
-       if (IS_ERR(primary_state)) {
-               ret = PTR_ERR(primary_state);
-               goto fail;
-       }
-
-       ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
+       ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, crtc);
        if (ret != 0)
                goto fail;
        drm_atomic_set_fb_for_plane(primary_state, set->fb);
@@ -1451,8 +1511,8 @@ fail:
 
        return ret;
 backoff:
-       drm_atomic_legacy_backoff(state);
        drm_atomic_state_clear(state);
+       drm_atomic_legacy_backoff(state);
 
        /*
         * Someone might have exchanged the framebuffer while we dropped locks
@@ -1517,8 +1577,8 @@ fail:
 
        return ret;
 backoff:
-       drm_atomic_legacy_backoff(state);
        drm_atomic_state_clear(state);
+       drm_atomic_legacy_backoff(state);
 
        goto retry;
 }
@@ -1576,8 +1636,8 @@ fail:
 
        return ret;
 backoff:
-       drm_atomic_legacy_backoff(state);
        drm_atomic_state_clear(state);
+       drm_atomic_legacy_backoff(state);
 
        goto retry;
 }
@@ -1635,8 +1695,8 @@ fail:
 
        return ret;
 backoff:
-       drm_atomic_legacy_backoff(state);
        drm_atomic_state_clear(state);
+       drm_atomic_legacy_backoff(state);
 
        goto retry;
 }
@@ -1691,7 +1751,7 @@ retry:
                goto fail;
        }
 
-       ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
+       ret = drm_atomic_set_crtc_for_plane(state, plane, crtc);
        if (ret != 0)
                goto fail;
        drm_atomic_set_fb_for_plane(plane_state, fb);
@@ -1714,8 +1774,8 @@ fail:
 
        return ret;
 backoff:
-       drm_atomic_legacy_backoff(state);
        drm_atomic_state_clear(state);
+       drm_atomic_legacy_backoff(state);
 
        /*
         * Someone might have exchanged the framebuffer while we dropped locks
index e6c169152bf1f57e38d75a716dac3816950f72eb..de79283eaea720ba0dc49cab73060a8dfee3d3ca 100644 (file)
@@ -683,7 +683,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
        drm_modeset_lock_init(&crtc->mutex);
        ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
        if (ret)
-               goto out;
+               return ret;
 
        crtc->base.properties = &crtc->properties;
 
@@ -697,9 +697,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
        if (cursor)
                cursor->possible_crtcs = 1 << drm_crtc_index(crtc);
 
- out:
-
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL(drm_crtc_init_with_planes);
 
@@ -723,6 +721,10 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
        drm_mode_object_put(dev, &crtc->base);
        list_del(&crtc->head);
        dev->mode_config.num_crtc--;
+
+       WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state);
+       if (crtc->state && crtc->funcs->atomic_destroy_state)
+               crtc->funcs->atomic_destroy_state(crtc, crtc->state);
 }
 EXPORT_SYMBOL(drm_crtc_cleanup);
 
@@ -869,6 +871,8 @@ int drm_connector_init(struct drm_device *dev,
 
        drm_connector_get_cmdline_mode(connector);
 
+       /* We should add connectors at the end to avoid upsetting the connector
+        * index too much. */
        list_add_tail(&connector->head, &dev->mode_config.connector_list);
        dev->mode_config.num_connector++;
 
@@ -918,6 +922,11 @@ void drm_connector_cleanup(struct drm_connector *connector)
        connector->name = NULL;
        list_del(&connector->head);
        dev->mode_config.num_connector--;
+
+       WARN_ON(connector->state && !connector->funcs->atomic_destroy_state);
+       if (connector->state && connector->funcs->atomic_destroy_state)
+               connector->funcs->atomic_destroy_state(connector,
+                                                      connector->state);
 }
 EXPORT_SYMBOL(drm_connector_cleanup);
 
@@ -932,6 +941,9 @@ unsigned int drm_connector_index(struct drm_connector *connector)
 {
        unsigned int index = 0;
        struct drm_connector *tmp;
+       struct drm_mode_config *config = &connector->dev->mode_config;
+
+       WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
 
        list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) {
                if (tmp == connector)
@@ -1152,11 +1164,11 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
 {
        int ret;
 
-       drm_modeset_lock_all(dev);
-
        ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
        if (ret)
-               goto out;
+               return ret;
+
+       drm_modeset_lock_init(&plane->mutex);
 
        plane->base.properties = &plane->properties;
        plane->dev = dev;
@@ -1166,8 +1178,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
        if (!plane->format_types) {
                DRM_DEBUG_KMS("out of memory when allocating plane\n");
                drm_mode_object_put(dev, &plane->base);
-               ret = -ENOMEM;
-               goto out;
+               return -ENOMEM;
        }
 
        memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
@@ -1184,10 +1195,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
                                   dev->mode_config.plane_type_property,
                                   plane->type);
 
- out:
-       drm_modeset_unlock_all(dev);
-
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL(drm_universal_plane_init);
 
@@ -1245,6 +1253,10 @@ void drm_plane_cleanup(struct drm_plane *plane)
        if (plane->type == DRM_PLANE_TYPE_OVERLAY)
                dev->mode_config.num_overlay_plane--;
        drm_modeset_unlock_all(dev);
+
+       WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);
+       if (plane->state && plane->funcs->atomic_destroy_state)
+               plane->funcs->atomic_destroy_state(plane, plane->state);
 }
 EXPORT_SYMBOL(drm_plane_cleanup);
 
@@ -1387,12 +1399,13 @@ EXPORT_SYMBOL(drm_mode_create_dvi_i_properties);
  * responsible for allocating a list of format names and passing them to
  * this routine.
  */
-int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
+int drm_mode_create_tv_properties(struct drm_device *dev,
+                                 unsigned int num_modes,
                                  char *modes[])
 {
        struct drm_property *tv_selector;
        struct drm_property *tv_subconnector;
-       int i;
+       unsigned int i;
 
        if (dev->mode_config.tv_select_subconnector_property)
                return 0;
@@ -1490,7 +1503,7 @@ EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
  * connectors.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_create_aspect_ratio_property(struct drm_device *dev)
 {
@@ -1534,6 +1547,30 @@ int drm_mode_create_dirty_info_property(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_mode_create_dirty_info_property);
 
+/**
+ * drm_mode_create_suggested_offset_properties - create suggests offset properties
+ * @dev: DRM device
+ *
+ * Create the the suggested x/y offset property for connectors.
+ */
+int drm_mode_create_suggested_offset_properties(struct drm_device *dev)
+{
+       if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property)
+               return 0;
+
+       dev->mode_config.suggested_x_property =
+               drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff);
+
+       dev->mode_config.suggested_y_property =
+               drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff);
+
+       if (dev->mode_config.suggested_x_property == NULL ||
+           dev->mode_config.suggested_y_property == NULL)
+               return -ENOMEM;
+       return 0;
+}
+EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties);
+
 static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group)
 {
        uint32_t total_objects = 0;
@@ -1650,7 +1687,7 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
  * the caller.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 static int drm_crtc_convert_umode(struct drm_display_mode *out,
                                  const struct drm_mode_modeinfo *in)
@@ -1693,7 +1730,7 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getresources(struct drm_device *dev, void *data,
                          struct drm_file *file_priv)
@@ -1744,7 +1781,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
        card_res->count_fbs = fb_count;
        mutex_unlock(&file_priv->fbs_lock);
 
-       drm_modeset_lock_all(dev);
+       /* mode_config.mutex protects the connector list against e.g. DP MST
+        * connector hot-adding. CRTC/Plane lists are invariant. */
+       mutex_lock(&dev->mode_config.mutex);
        if (!drm_is_primary_client(file_priv)) {
 
                mode_group = NULL;
@@ -1864,7 +1903,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
                  card_res->count_connectors, card_res->count_encoders);
 
 out:
-       drm_modeset_unlock_all(dev);
+       mutex_unlock(&dev->mode_config.mutex);
        return ret;
 }
 
@@ -1879,26 +1918,22 @@ out:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getcrtc(struct drm_device *dev,
                     void *data, struct drm_file *file_priv)
 {
        struct drm_mode_crtc *crtc_resp = data;
        struct drm_crtc *crtc;
-       int ret = 0;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
 
-       drm_modeset_lock_all(dev);
-
        crtc = drm_crtc_find(dev, crtc_resp->crtc_id);
-       if (!crtc) {
-               ret = -ENOENT;
-               goto out;
-       }
+       if (!crtc)
+               return -ENOENT;
 
+       drm_modeset_lock_crtc(crtc, crtc->primary);
        crtc_resp->x = crtc->x;
        crtc_resp->y = crtc->y;
        crtc_resp->gamma_size = crtc->gamma_size;
@@ -1915,10 +1950,9 @@ int drm_mode_getcrtc(struct drm_device *dev,
        } else {
                crtc_resp->mode_valid = 0;
        }
+       drm_modeset_unlock_crtc(crtc);
 
-out:
-       drm_modeset_unlock_all(dev);
-       return ret;
+       return 0;
 }
 
 static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
@@ -1934,6 +1968,15 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
        return true;
 }
 
+static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector)
+{
+       /* For atomic drivers only state objects are synchronously updated and
+        * protected by modeset locks, so check those first. */
+       if (connector->state)
+               return connector->state->best_encoder;
+       return connector->encoder;
+}
+
 /**
  * drm_mode_getconnector - get connector configuration
  * @dev: drm device for the ioctl
@@ -1945,13 +1988,14 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getconnector(struct drm_device *dev, void *data,
                          struct drm_file *file_priv)
 {
        struct drm_mode_get_connector *out_resp = data;
        struct drm_connector *connector;
+       struct drm_encoder *encoder;
        struct drm_display_mode *mode;
        int mode_count = 0;
        int props_count = 0;
@@ -2007,8 +2051,10 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
        out_resp->subpixel = connector->display_info.subpixel_order;
        out_resp->connection = connector->status;
        drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
-       if (connector->encoder)
-               out_resp->encoder_id = connector->encoder->base.id;
+
+       encoder = drm_connector_get_encoder(connector);
+       if (encoder)
+               out_resp->encoder_id = encoder->base.id;
        else
                out_resp->encoder_id = 0;
        drm_modeset_unlock(&dev->mode_config.connection_mutex);
@@ -2078,6 +2124,33 @@ out:
        return ret;
 }
 
+static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder)
+{
+       struct drm_connector *connector;
+       struct drm_device *dev = encoder->dev;
+       bool uses_atomic = false;
+
+       /* For atomic drivers only state objects are synchronously updated and
+        * protected by modeset locks, so check those first. */
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (!connector->state)
+                       continue;
+
+               uses_atomic = true;
+
+               if (connector->state->best_encoder != encoder)
+                       continue;
+
+               return connector->state->crtc;
+       }
+
+       /* Don't return stale data (e.g. pending async disable). */
+       if (uses_atomic)
+               return NULL;
+
+       return encoder->crtc;
+}
+
 /**
  * drm_mode_getencoder - get encoder configuration
  * @dev: drm device for the ioctl
@@ -2089,37 +2162,38 @@ out:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getencoder(struct drm_device *dev, void *data,
                        struct drm_file *file_priv)
 {
        struct drm_mode_get_encoder *enc_resp = data;
        struct drm_encoder *encoder;
-       int ret = 0;
+       struct drm_crtc *crtc;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
 
-       drm_modeset_lock_all(dev);
        encoder = drm_encoder_find(dev, enc_resp->encoder_id);
-       if (!encoder) {
-               ret = -ENOENT;
-               goto out;
-       }
+       if (!encoder)
+               return -ENOENT;
 
-       if (encoder->crtc)
+       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+       crtc = drm_encoder_get_crtc(encoder);
+       if (crtc)
+               enc_resp->crtc_id = crtc->base.id;
+       else if (encoder->crtc)
                enc_resp->crtc_id = encoder->crtc->base.id;
        else
                enc_resp->crtc_id = 0;
+       drm_modeset_unlock(&dev->mode_config.connection_mutex);
+
        enc_resp->encoder_type = encoder->encoder_type;
        enc_resp->encoder_id = encoder->base.id;
        enc_resp->possible_crtcs = encoder->possible_crtcs;
        enc_resp->possible_clones = encoder->possible_clones;
 
-out:
-       drm_modeset_unlock_all(dev);
-       return ret;
+       return 0;
 }
 
 /**
@@ -2133,7 +2207,7 @@ out:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getplane_res(struct drm_device *dev, void *data,
                          struct drm_file *file_priv)
@@ -2142,13 +2216,12 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
        struct drm_mode_config *config;
        struct drm_plane *plane;
        uint32_t __user *plane_ptr;
-       int copied = 0, ret = 0;
+       int copied = 0;
        unsigned num_planes;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
 
-       drm_modeset_lock_all(dev);
        config = &dev->mode_config;
 
        if (file_priv->universal_planes)
@@ -2164,6 +2237,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
            (plane_resp->count_planes >= num_planes)) {
                plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
 
+               /* Plane lists are invariant, no locking needed. */
                list_for_each_entry(plane, &config->plane_list, head) {
                        /*
                         * Unless userspace set the 'universal planes'
@@ -2173,18 +2247,14 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
                            !file_priv->universal_planes)
                                continue;
 
-                       if (put_user(plane->base.id, plane_ptr + copied)) {
-                               ret = -EFAULT;
-                               goto out;
-                       }
+                       if (put_user(plane->base.id, plane_ptr + copied))
+                               return -EFAULT;
                        copied++;
                }
        }
        plane_resp->count_planes = num_planes;
 
-out:
-       drm_modeset_unlock_all(dev);
-       return ret;
+       return 0;
 }
 
 /**
@@ -2198,7 +2268,7 @@ out:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getplane(struct drm_device *dev, void *data,
                      struct drm_file *file_priv)
@@ -2206,18 +2276,15 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
        struct drm_mode_get_plane *plane_resp = data;
        struct drm_plane *plane;
        uint32_t __user *format_ptr;
-       int ret = 0;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
 
-       drm_modeset_lock_all(dev);
        plane = drm_plane_find(dev, plane_resp->plane_id);
-       if (!plane) {
-               ret = -ENOENT;
-               goto out;
-       }
+       if (!plane)
+               return -ENOENT;
 
+       drm_modeset_lock(&plane->mutex, NULL);
        if (plane->crtc)
                plane_resp->crtc_id = plane->crtc->base.id;
        else
@@ -2227,6 +2294,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
                plane_resp->fb_id = plane->fb->base.id;
        else
                plane_resp->fb_id = 0;
+       drm_modeset_unlock(&plane->mutex);
 
        plane_resp->plane_id = plane->base.id;
        plane_resp->possible_crtcs = plane->possible_crtcs;
@@ -2242,15 +2310,12 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
                if (copy_to_user(format_ptr,
                                 plane->format_types,
                                 sizeof(uint32_t) * plane->format_count)) {
-                       ret = -EFAULT;
-                       goto out;
+                       return -EFAULT;
                }
        }
        plane_resp->count_format_types = plane->format_count;
 
-out:
-       drm_modeset_unlock_all(dev);
-       return ret;
+       return 0;
 }
 
 /*
@@ -2273,7 +2338,7 @@ static int __setplane_internal(struct drm_plane *plane,
 {
        int ret = 0;
        unsigned int fb_width, fb_height;
-       int i;
+       unsigned int i;
 
        /* No fb means shut it down */
        if (!fb) {
@@ -2377,13 +2442,12 @@ static int setplane_internal(struct drm_plane *plane,
  * valid crtc).
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_setplane(struct drm_device *dev, void *data,
                      struct drm_file *file_priv)
 {
        struct drm_mode_set_plane *plane_req = data;
-       struct drm_mode_object *obj;
        struct drm_plane *plane;
        struct drm_crtc *crtc = NULL;
        struct drm_framebuffer *fb = NULL;
@@ -2406,14 +2470,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
         * First, find the plane, crtc, and fb objects.  If not available,
         * we don't bother to call the driver.
         */
-       obj = drm_mode_object_find(dev, plane_req->plane_id,
-                                  DRM_MODE_OBJECT_PLANE);
-       if (!obj) {
+       plane = drm_plane_find(dev, plane_req->plane_id);
+       if (!plane) {
                DRM_DEBUG_KMS("Unknown plane ID %d\n",
                              plane_req->plane_id);
                return -ENOENT;
        }
-       plane = obj_to_plane(obj);
 
        if (plane_req->fb_id) {
                fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
@@ -2423,14 +2485,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
                        return -ENOENT;
                }
 
-               obj = drm_mode_object_find(dev, plane_req->crtc_id,
-                                          DRM_MODE_OBJECT_CRTC);
-               if (!obj) {
+               crtc = drm_crtc_find(dev, plane_req->crtc_id);
+               if (!crtc) {
                        DRM_DEBUG_KMS("Unknown crtc ID %d\n",
                                      plane_req->crtc_id);
                        return -ENOENT;
                }
-               crtc = obj_to_crtc(obj);
        }
 
        /*
@@ -2452,7 +2512,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
  * interface. The only thing it adds is correct refcounting dance.
  * 
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_set_config_internal(struct drm_mode_set *set)
 {
@@ -2545,7 +2605,7 @@ EXPORT_SYMBOL(drm_crtc_check_viewport);
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_setcrtc(struct drm_device *dev, void *data,
                     struct drm_file *file_priv)
@@ -2708,7 +2768,7 @@ out:
  * userspace wants to make use of these capabilities.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 static int drm_mode_cursor_universal(struct drm_crtc *crtc,
                                     struct drm_mode_cursor2 *req,
@@ -2809,7 +2869,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
         * If this crtc has a universal cursor plane, call that plane's update
         * handler rather than using legacy cursor handlers.
         */
-       drm_modeset_lock_crtc(crtc);
+       drm_modeset_lock_crtc(crtc, crtc->cursor);
        if (crtc->cursor) {
                ret = drm_mode_cursor_universal(crtc, req, file_priv);
                goto out;
@@ -2856,7 +2916,7 @@ out:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_cursor_ioctl(struct drm_device *dev,
                          void *data, struct drm_file *file_priv)
@@ -2883,7 +2943,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_cursor2_ioctl(struct drm_device *dev,
                           void *data, struct drm_file *file_priv)
@@ -2947,7 +3007,7 @@ EXPORT_SYMBOL(drm_mode_legacy_fb_format);
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_addfb(struct drm_device *dev,
                   void *data, struct drm_file *file_priv)
@@ -2970,7 +3030,7 @@ int drm_mode_addfb(struct drm_device *dev,
 
        or->fb_id = r.fb_id;
 
-       return ret;
+       return 0;
 }
 
 static int format_check(const struct drm_mode_fb_cmd2 *r)
@@ -3152,7 +3212,7 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_addfb2(struct drm_device *dev,
                    void *data, struct drm_file *file_priv)
@@ -3180,7 +3240,7 @@ int drm_mode_addfb2(struct drm_device *dev,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_rmfb(struct drm_device *dev,
                   void *data, struct drm_file *file_priv)
@@ -3234,7 +3294,7 @@ fail_lookup:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getfb(struct drm_device *dev,
                   void *data, struct drm_file *file_priv)
@@ -3295,7 +3355,7 @@ int drm_mode_getfb(struct drm_device *dev,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
                           void *data, struct drm_file *file_priv)
@@ -3375,7 +3435,7 @@ out_err1:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 void drm_fb_release(struct drm_file *priv)
 {
@@ -3448,7 +3508,7 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
 
        property->flags = flags;
        property->num_values = num_values;
-       INIT_LIST_HEAD(&property->enum_blob_list);
+       INIT_LIST_HEAD(&property->enum_list);
 
        if (name) {
                strncpy(property->name, name, DRM_PROP_NAME_LEN);
@@ -3670,8 +3730,8 @@ int drm_property_add_enum(struct drm_property *property, int index,
                        (value > 63))
                return -EINVAL;
 
-       if (!list_empty(&property->enum_blob_list)) {
-               list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
+       if (!list_empty(&property->enum_list)) {
+               list_for_each_entry(prop_enum, &property->enum_list, head) {
                        if (prop_enum->value == value) {
                                strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
                                prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
@@ -3689,7 +3749,7 @@ int drm_property_add_enum(struct drm_property *property, int index,
        prop_enum->value = value;
 
        property->values[index] = value;
-       list_add_tail(&prop_enum->head, &property->enum_blob_list);
+       list_add_tail(&prop_enum->head, &property->enum_list);
        return 0;
 }
 EXPORT_SYMBOL(drm_property_add_enum);
@@ -3706,7 +3766,7 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
 {
        struct drm_property_enum *prop_enum, *pt;
 
-       list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) {
+       list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) {
                list_del(&prop_enum->head);
                kfree(prop_enum);
        }
@@ -3809,17 +3869,20 @@ int drm_object_property_get_value(struct drm_mode_object *obj,
 EXPORT_SYMBOL(drm_object_property_get_value);
 
 /**
- * drm_mode_getproperty_ioctl - get the current value of a connector's property
+ * drm_mode_getproperty_ioctl - get the property metadata
  * @dev: DRM device
  * @data: ioctl data
  * @file_priv: DRM file info
  *
- * This function retrieves the current value for an connectors's property.
+ * This function retrieves the metadata for a given property, like the different
+ * possible values for an enum property or the limits for a range property.
+ *
+ * Blob properties are special
  *
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getproperty_ioctl(struct drm_device *dev,
                               void *data, struct drm_file *file_priv)
@@ -3827,16 +3890,12 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
        struct drm_mode_get_property *out_resp = data;
        struct drm_property *property;
        int enum_count = 0;
-       int blob_count = 0;
        int value_count = 0;
        int ret = 0, i;
        int copied;
        struct drm_property_enum *prop_enum;
        struct drm_mode_property_enum __user *enum_ptr;
-       struct drm_property_blob *prop_blob;
-       uint32_t __user *blob_id_ptr;
        uint64_t __user *values_ptr;
-       uint32_t __user *blob_length_ptr;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
@@ -3850,11 +3909,8 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
 
        if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
                        drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
-               list_for_each_entry(prop_enum, &property->enum_blob_list, head)
+               list_for_each_entry(prop_enum, &property->enum_list, head)
                        enum_count++;
-       } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
-               list_for_each_entry(prop_blob, &property->enum_blob_list, head)
-                       blob_count++;
        }
 
        value_count = property->num_values;
@@ -3879,7 +3935,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
                if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
                        copied = 0;
                        enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
-                       list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
+                       list_for_each_entry(prop_enum, &property->enum_list, head) {
 
                                if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) {
                                        ret = -EFAULT;
@@ -3897,35 +3953,24 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
                out_resp->count_enum_blobs = enum_count;
        }
 
-       if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
-               if ((out_resp->count_enum_blobs >= blob_count) && blob_count) {
-                       copied = 0;
-                       blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr;
-                       blob_length_ptr = (uint32_t __user *)(unsigned long)out_resp->values_ptr;
-
-                       list_for_each_entry(prop_blob, &property->enum_blob_list, head) {
-                               if (put_user(prop_blob->base.id, blob_id_ptr + copied)) {
-                                       ret = -EFAULT;
-                                       goto done;
-                               }
-
-                               if (put_user(prop_blob->length, blob_length_ptr + copied)) {
-                                       ret = -EFAULT;
-                                       goto done;
-                               }
-
-                               copied++;
-                       }
-               }
-               out_resp->count_enum_blobs = blob_count;
-       }
+       /*
+        * NOTE: The idea seems to have been to use this to read all the blob
+        * property values. But nothing ever added them to the corresponding
+        * list, userspace always used the special-purpose get_blob ioctl to
+        * read the value for a blob property. It also doesn't make a lot of
+        * sense to return values here when everything else is just metadata for
+        * the property itself.
+        */
+       if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
+               out_resp->count_enum_blobs = 0;
 done:
        drm_modeset_unlock_all(dev);
        return ret;
 }
 
-static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length,
-                                                         void *data)
+static struct drm_property_blob *
+drm_property_create_blob(struct drm_device *dev, size_t length,
+                        const void *data)
 {
        struct drm_property_blob *blob;
        int ret;
@@ -3971,7 +4016,7 @@ static void drm_property_destroy_blob(struct drm_device *dev,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getblob_ioctl(struct drm_device *dev,
                           void *data, struct drm_file *file_priv)
@@ -4016,14 +4061,14 @@ done:
  * them more meaningful names.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_connector_set_path_property(struct drm_connector *connector,
-                                        char *path)
+                                        const char *path)
 {
        struct drm_device *dev = connector->dev;
-       int ret, size;
-       size = strlen(path) + 1;
+       size_t size = strlen(path) + 1;
+       int ret;
 
        connector->path_blob_ptr = drm_property_create_blob(connector->dev,
                                                            size, path);
@@ -4046,13 +4091,14 @@ EXPORT_SYMBOL(drm_mode_connector_set_path_property);
  * connector's edid property.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_connector_update_edid_property(struct drm_connector *connector,
-                                           struct edid *edid)
+                                           const struct edid *edid)
 {
        struct drm_device *dev = connector->dev;
-       int ret, size;
+       size_t size;
+       int ret;
 
        /* ignore requests to set edid when overridden */
        if (connector->override_edid)
@@ -4142,7 +4188,7 @@ static bool drm_property_change_is_valid(struct drm_property *property,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
                                       void *data, struct drm_file *file_priv)
@@ -4225,7 +4271,7 @@ int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
 EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
 
 /**
- * drm_mode_getproperty_ioctl - get the current value of a object's property
+ * drm_mode_obj_get_properties_ioctl - get the current value of a object's property
  * @dev: DRM device
  * @data: ioctl data
  * @file_priv: DRM file info
@@ -4237,7 +4283,7 @@ EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
                                      struct drm_file *file_priv)
@@ -4309,7 +4355,7 @@ out:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
                                    struct drm_file *file_priv)
@@ -4381,7 +4427,7 @@ out:
  * possible_clones and possible_crtcs bitmasks.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_connector_attach_encoder(struct drm_connector *connector,
                                      struct drm_encoder *encoder)
@@ -4408,7 +4454,7 @@ EXPORT_SYMBOL(drm_mode_connector_attach_encoder);
  * fixed gamma table size.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
                                 int gamma_size)
@@ -4437,7 +4483,7 @@ EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_gamma_set_ioctl(struct drm_device *dev,
                             void *data, struct drm_file *file_priv)
@@ -4509,7 +4555,7 @@ out:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_gamma_get_ioctl(struct drm_device *dev,
                             void *data, struct drm_file *file_priv)
@@ -4575,7 +4621,7 @@ out:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_page_flip_ioctl(struct drm_device *dev,
                             void *data, struct drm_file *file_priv)
@@ -4598,7 +4644,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
        if (!crtc)
                return -ENOENT;
 
-       drm_modeset_lock_crtc(crtc);
+       drm_modeset_lock_crtc(crtc, crtc->primary);
        if (crtc->primary->fb == NULL) {
                /* The framebuffer is currently unbound, presumably
                 * due to a hotplug event, that userspace has not
@@ -4741,7 +4787,7 @@ EXPORT_SYMBOL(drm_mode_config_reset);
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_create_dumb_ioctl(struct drm_device *dev,
                               void *data, struct drm_file *file_priv)
@@ -4768,6 +4814,16 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev,
        if (PAGE_ALIGN(size) == 0)
                return -EINVAL;
 
+       /*
+        * handle, pitch and size are output parameters. Zero them out to
+        * prevent drivers from accidentally using uninitialized data. Since
+        * not all existing userspace is clearing these fields properly we
+        * cannot reject IOCTL with garbage in them.
+        */
+       args->handle = 0;
+       args->pitch = 0;
+       args->size = 0;
+
        return dev->driver->dumb_create(file_priv, dev, args);
 }
 
@@ -4783,7 +4839,7 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
                             void *data, struct drm_file *file_priv)
@@ -4810,7 +4866,7 @@ int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
                                void *data, struct drm_file *file_priv)
index dc98b8f781680f39f990ae236cac4998e12893f0..5682d7e9f1ec28a825263097d7009fdbf5b5cdd5 100644 (file)
@@ -1799,17 +1799,27 @@ static int drm_dp_send_up_ack_reply(struct drm_dp_mst_topology_mgr *mgr,
        return 0;
 }
 
-static int drm_dp_get_vc_payload_bw(int dp_link_bw, int dp_link_count)
+static bool drm_dp_get_vc_payload_bw(int dp_link_bw,
+                                    int dp_link_count,
+                                    int *out)
 {
        switch (dp_link_bw) {
+       default:
+               DRM_DEBUG_KMS("invalid link bandwidth in DPCD: %x (link count: %d)\n",
+                             dp_link_bw, dp_link_count);
+               return false;
+
        case DP_LINK_BW_1_62:
-               return 3 * dp_link_count;
+               *out = 3 * dp_link_count;
+               break;
        case DP_LINK_BW_2_7:
-               return 5 * dp_link_count;
+               *out = 5 * dp_link_count;
+               break;
        case DP_LINK_BW_5_4:
-               return 10 * dp_link_count;
+               *out = 10 * dp_link_count;
+               break;
        }
-       BUG();
+       return true;
 }
 
 /**
@@ -1841,7 +1851,13 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
                        goto out_unlock;
                }
 
-               mgr->pbn_div = drm_dp_get_vc_payload_bw(mgr->dpcd[1], mgr->dpcd[2] & DP_MAX_LANE_COUNT_MASK);
+               if (!drm_dp_get_vc_payload_bw(mgr->dpcd[1],
+                                             mgr->dpcd[2] & DP_MAX_LANE_COUNT_MASK,
+                                             &mgr->pbn_div)) {
+                       ret = -EINVAL;
+                       goto out_unlock;
+               }
+
                mgr->total_pbn = 2560;
                mgr->total_slots = DIV_ROUND_UP(mgr->total_pbn, mgr->pbn_div);
                mgr->avail_slots = mgr->total_slots;
index 2e5c7d941313e796f3145310d2f21254893940b4..4f41377b0b80963f9ce84b3492412d025924652b 100644 (file)
@@ -535,6 +535,8 @@ static void drm_fs_inode_free(struct inode *inode)
  * The initial ref-count of the object is 1. Use drm_dev_ref() and
  * drm_dev_unref() to take and drop further ref-counts.
  *
+ * Note that for purely virtual devices @parent can be NULL.
+ *
  * RETURNS:
  * Pointer to new DRM device, or NULL if out of memory.
  */
index 45aaa6f5ef3657ac2d52cd2b3fb8edfb7b52caa9..a7b5a71856a72a3956cc4f3c6fbe90442e1a535f 100644 (file)
@@ -1125,9 +1125,9 @@ EXPORT_SYMBOL(drm_edid_is_valid);
  * Return: 0 on success or -1 on failure.
  */
 static int
-drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
-                     int block, int len)
+drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int block, size_t len)
 {
+       struct i2c_adapter *adapter = data;
        unsigned char start = block * EDID_LENGTH;
        unsigned char segment = block >> 1;
        unsigned char xfers = segment ? 3 : 2;
@@ -1184,8 +1184,26 @@ static bool drm_edid_is_zero(u8 *in_edid, int length)
        return true;
 }
 
-static u8 *
-drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
+/**
+ * drm_do_get_edid - get EDID data using a custom EDID block read function
+ * @connector: connector we're probing
+ * @get_edid_block: EDID block read function
+ * @data: private data passed to the block read function
+ *
+ * When the I2C adapter connected to the DDC bus is hidden behind a device that
+ * exposes a different interface to read EDID blocks this function can be used
+ * to get EDID data using a custom block read function.
+ *
+ * As in the general case the DDC bus is accessible by the kernel at the I2C
+ * level, drivers must make all reasonable efforts to expose it as an I2C
+ * adapter and use drm_get_edid() instead of abusing this function.
+ *
+ * Return: Pointer to valid EDID or NULL if we couldn't find any.
+ */
+struct edid *drm_do_get_edid(struct drm_connector *connector,
+       int (*get_edid_block)(void *data, u8 *buf, unsigned int block,
+                             size_t len),
+       void *data)
 {
        int i, j = 0, valid_extensions = 0;
        u8 *block, *new;
@@ -1196,7 +1214,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
 
        /* base block fetch */
        for (i = 0; i < 4; i++) {
-               if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH))
+               if (get_edid_block(data, block, 0, EDID_LENGTH))
                        goto out;
                if (drm_edid_block_valid(block, 0, print_bad_edid))
                        break;
@@ -1210,7 +1228,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
 
        /* if there's no extensions, we're done */
        if (block[0x7e] == 0)
-               return block;
+               return (struct edid *)block;
 
        new = krealloc(block, (block[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL);
        if (!new)
@@ -1219,7 +1237,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
 
        for (j = 1; j <= block[0x7e]; j++) {
                for (i = 0; i < 4; i++) {
-                       if (drm_do_probe_ddc_edid(adapter,
+                       if (get_edid_block(data,
                                  block + (valid_extensions + 1) * EDID_LENGTH,
                                  j, EDID_LENGTH))
                                goto out;
@@ -1247,7 +1265,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
                block = new;
        }
 
-       return block;
+       return (struct edid *)block;
 
 carp:
        if (print_bad_edid) {
@@ -1260,6 +1278,7 @@ out:
        kfree(block);
        return NULL;
 }
+EXPORT_SYMBOL_GPL(drm_do_get_edid);
 
 /**
  * drm_probe_ddc() - probe DDC presence
@@ -1289,12 +1308,10 @@ EXPORT_SYMBOL(drm_probe_ddc);
 struct edid *drm_get_edid(struct drm_connector *connector,
                          struct i2c_adapter *adapter)
 {
-       struct edid *edid = NULL;
-
-       if (drm_probe_ddc(adapter))
-               edid = (struct edid *)drm_do_get_edid(connector, adapter);
+       if (!drm_probe_ddc(adapter))
+               return NULL;
 
-       return edid;
+       return drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter);
 }
 EXPORT_SYMBOL(drm_get_edid);
 
index 0a235fe61c9b9bfd929a1f4a71461bc6ad2bd3d7..732cb6f8e653f58dee7102f0bb11b797cde2f5ad 100644 (file)
@@ -254,8 +254,7 @@ static void *edid_load(struct drm_connector *connector, const char *name,
            name, connector_name);
 
 out:
-       if (fw)
-               release_firmware(fw);
+       release_firmware(fw);
        return edid;
 }
 
index f9c7fa3d00124e9d4cd126cccd3a8f78ee0d7836..43d9b950ef9fd03bb0f7eb267a0c46a01e6688c7 100644 (file)
 #include "drmP.h"
 #include "drm_flip_work.h"
 
+/**
+ * drm_flip_work_allocate_task - allocate a flip-work task
+ * @data: data associated to the task
+ * @flags: allocator flags
+ *
+ * Allocate a drm_flip_task object and attach private data to it.
+ */
+struct drm_flip_task *drm_flip_work_allocate_task(void *data, gfp_t flags)
+{
+       struct drm_flip_task *task;
+
+       task = kzalloc(sizeof(*task), flags);
+       if (task)
+               task->data = data;
+
+       return task;
+}
+EXPORT_SYMBOL(drm_flip_work_allocate_task);
+
+/**
+ * drm_flip_work_queue_task - queue a specific task
+ * @work: the flip-work
+ * @task: the task to handle
+ *
+ * Queues task, that will later be run (passed back to drm_flip_func_t
+ * func) on a work queue after drm_flip_work_commit() is called.
+ */
+void drm_flip_work_queue_task(struct drm_flip_work *work,
+                             struct drm_flip_task *task)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&work->lock, flags);
+       list_add_tail(&task->node, &work->queued);
+       spin_unlock_irqrestore(&work->lock, flags);
+}
+EXPORT_SYMBOL(drm_flip_work_queue_task);
+
 /**
  * drm_flip_work_queue - queue work
  * @work: the flip-work
  */
 void drm_flip_work_queue(struct drm_flip_work *work, void *val)
 {
-       if (kfifo_put(&work->fifo, val)) {
-               atomic_inc(&work->pending);
+       struct drm_flip_task *task;
+
+       task = drm_flip_work_allocate_task(val,
+                               drm_can_sleep() ? GFP_KERNEL : GFP_ATOMIC);
+       if (task) {
+               drm_flip_work_queue_task(work, task);
        } else {
-               DRM_ERROR("%s fifo full!\n", work->name);
+               DRM_ERROR("%s could not allocate task!\n", work->name);
                work->func(work, val);
        }
 }
@@ -56,9 +98,12 @@ EXPORT_SYMBOL(drm_flip_work_queue);
 void drm_flip_work_commit(struct drm_flip_work *work,
                struct workqueue_struct *wq)
 {
-       uint32_t pending = atomic_read(&work->pending);
-       atomic_add(pending, &work->count);
-       atomic_sub(pending, &work->pending);
+       unsigned long flags;
+
+       spin_lock_irqsave(&work->lock, flags);
+       list_splice_tail(&work->queued, &work->commited);
+       INIT_LIST_HEAD(&work->queued);
+       spin_unlock_irqrestore(&work->lock, flags);
        queue_work(wq, &work->worker);
 }
 EXPORT_SYMBOL(drm_flip_work_commit);
@@ -66,47 +111,46 @@ EXPORT_SYMBOL(drm_flip_work_commit);
 static void flip_worker(struct work_struct *w)
 {
        struct drm_flip_work *work = container_of(w, struct drm_flip_work, worker);
-       uint32_t count = atomic_read(&work->count);
-       void *val = NULL;
+       struct list_head tasks;
+       unsigned long flags;
+
+       while (1) {
+               struct drm_flip_task *task, *tmp;
+
+               INIT_LIST_HEAD(&tasks);
+               spin_lock_irqsave(&work->lock, flags);
+               list_splice_tail(&work->commited, &tasks);
+               INIT_LIST_HEAD(&work->commited);
+               spin_unlock_irqrestore(&work->lock, flags);
 
-       atomic_sub(count, &work->count);
+               if (list_empty(&tasks))
+                       break;
 
-       while(count--)
-               if (!WARN_ON(!kfifo_get(&work->fifo, &val)))
-                       work->func(work, val);
+               list_for_each_entry_safe(task, tmp, &tasks, node) {
+                       work->func(work, task->data);
+                       kfree(task);
+               }
+       }
 }
 
 /**
  * drm_flip_work_init - initialize flip-work
  * @work: the flip-work to initialize
- * @size: the max queue depth
  * @name: debug name
  * @func: the callback work function
  *
  * Initializes/allocates resources for the flip-work
- *
- * RETURNS:
- * Zero on success, error code on failure.
  */
-int drm_flip_work_init(struct drm_flip_work *work, int size,
+void drm_flip_work_init(struct drm_flip_work *work,
                const char *name, drm_flip_func_t func)
 {
-       int ret;
-
        work->name = name;
-       atomic_set(&work->count, 0);
-       atomic_set(&work->pending, 0);
+       INIT_LIST_HEAD(&work->queued);
+       INIT_LIST_HEAD(&work->commited);
+       spin_lock_init(&work->lock);
        work->func = func;
 
-       ret = kfifo_alloc(&work->fifo, size, GFP_KERNEL);
-       if (ret) {
-               DRM_ERROR("could not allocate %s fifo\n", name);
-               return ret;
-       }
-
        INIT_WORK(&work->worker, flip_worker);
-
-       return 0;
 }
 EXPORT_SYMBOL(drm_flip_work_init);
 
@@ -118,7 +162,6 @@ EXPORT_SYMBOL(drm_flip_work_init);
  */
 void drm_flip_work_cleanup(struct drm_flip_work *work)
 {
-       WARN_ON(!kfifo_is_empty(&work->fifo));
-       kfifo_free(&work->fifo);
+       WARN_ON(!list_empty(&work->queued) || !list_empty(&work->commited));
 }
 EXPORT_SYMBOL(drm_flip_work_cleanup);
index f6ca51259fa3a90dbc46fff70d8e15dc5e483ba8..16a1647707136cb7207a83967af7235367e1ee73 100644 (file)
@@ -188,7 +188,7 @@ drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp)
 }
 
 /**
- * drm_gem_object_free - release resources bound to userspace handles
+ * drm_gem_object_handle_free - release resources bound to userspace handles
  * @obj: GEM object to clean up.
  *
  * Called after the last handle to the object has been closed
@@ -309,7 +309,7 @@ EXPORT_SYMBOL(drm_gem_dumb_destroy);
  * drm_gem_handle_create_tail - internal functions to create a handle
  * @file_priv: drm file-private structure to register the handle for
  * @obj: object to register
- * @handlep: pionter to return the created handle to the caller
+ * @handlep: pointer to return the created handle to the caller
  * 
  * This expects the dev->object_name_lock to be held already and will drop it
  * before returning. Used to avoid races in establishing new handles when
@@ -362,7 +362,7 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
 }
 
 /**
- * gem_handle_create - create a gem handle for an object
+ * drm_gem_handle_create - create a gem handle for an object
  * @file_priv: drm file-private structure to register the handle for
  * @obj: object to register
  * @handlep: pionter to return the created handle to the caller
@@ -371,10 +371,9 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
  * to the object, which includes a regular reference count. Callers
  * will likely want to dereference the object afterwards.
  */
-int
-drm_gem_handle_create(struct drm_file *file_priv,
-                      struct drm_gem_object *obj,
-                      u32 *handlep)
+int drm_gem_handle_create(struct drm_file *file_priv,
+                         struct drm_gem_object *obj,
+                         u32 *handlep)
 {
        mutex_lock(&obj->dev->object_name_lock);
 
index 0316310e2cc47400703418ea324e381cc65f8c8b..e419eedf751de6cb4c3f0b64b88dcd771cf594bc 100644 (file)
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_vma_manager.h>
 
-/*
+/**
+ * DOC: cma helpers
+ *
+ * The Contiguous Memory Allocator reserves a pool of memory at early boot
+ * that is used to service requests for large blocks of contiguous memory.
+ *
+ * The DRM GEM/CMA helpers use this allocator as a means to provide buffer
+ * objects that are physically contiguous in memory. This is useful for
+ * display drivers that are unable to map scattered buffers via an IOMMU.
+ */
+
+/**
  * __drm_gem_cma_create - Create a GEM CMA object without allocating memory
- * @drm: The drm device
- * @size: The GEM object size
+ * @drm: DRM device
+ * @size: size of the object to allocate
  *
- * This function creates and initializes a GEM CMA object of the given size, but
- * doesn't allocate any memory to back the object.
+ * This function creates and initializes a GEM CMA object of the given size,
+ * but doesn't allocate any memory to back the object.
  *
- * Return a struct drm_gem_cma_object* on success or ERR_PTR values on failure.
+ * Returns:
+ * A struct drm_gem_cma_object * on success or an ERR_PTR()-encoded negative
+ * error code on failure.
  */
 static struct drm_gem_cma_object *
-__drm_gem_cma_create(struct drm_device *drm, unsigned int size)
+__drm_gem_cma_create(struct drm_device *drm, size_t size)
 {
        struct drm_gem_cma_object *cma_obj;
        struct drm_gem_object *gem_obj;
@@ -69,14 +82,21 @@ error:
        return ERR_PTR(ret);
 }
 
-/*
+/**
  * drm_gem_cma_create - allocate an object with the given size
+ * @drm: DRM device
+ * @size: size of the object to allocate
+ *
+ * This function creates a CMA GEM object and allocates a contiguous chunk of
+ * memory as backing store. The backing memory has the writecombine attribute
+ * set.
  *
- * returns a struct drm_gem_cma_object* on success or ERR_PTR values
- * on failure.
+ * Returns:
+ * A struct drm_gem_cma_object * on success or an ERR_PTR()-encoded negative
+ * error code on failure.
  */
 struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm,
-               unsigned int size)
+                                             size_t size)
 {
        struct drm_gem_cma_object *cma_obj;
        int ret;
@@ -104,17 +124,26 @@ error:
 }
 EXPORT_SYMBOL_GPL(drm_gem_cma_create);
 
-/*
- * drm_gem_cma_create_with_handle - allocate an object with the given
- * size and create a gem handle on it
+/**
+ * drm_gem_cma_create_with_handle - allocate an object with the given size and
+ *     return a GEM handle to it
+ * @file_priv: DRM file-private structure to register the handle for
+ * @drm: DRM device
+ * @size: size of the object to allocate
+ * @handle: return location for the GEM handle
+ *
+ * This function creates a CMA GEM object, allocating a physically contiguous
+ * chunk of memory as backing store. The GEM object is then added to the list
+ * of object associated with the given file and a handle to it is returned.
  *
- * returns a struct drm_gem_cma_object* on success or ERR_PTR values
- * on failure.
+ * Returns:
+ * A struct drm_gem_cma_object * on success or an ERR_PTR()-encoded negative
+ * error code on failure.
  */
-static struct drm_gem_cma_object *drm_gem_cma_create_with_handle(
-               struct drm_file *file_priv,
-               struct drm_device *drm, unsigned int size,
-               unsigned int *handle)
+static struct drm_gem_cma_object *
+drm_gem_cma_create_with_handle(struct drm_file *file_priv,
+                              struct drm_device *drm, size_t size,
+                              uint32_t *handle)
 {
        struct drm_gem_cma_object *cma_obj;
        struct drm_gem_object *gem_obj;
@@ -145,16 +174,19 @@ err_handle_create:
        return ERR_PTR(ret);
 }
 
-/*
- * drm_gem_cma_free_object - (struct drm_driver)->gem_free_object callback
- * function
+/**
+ * drm_gem_cma_free_object - free resources associated with a CMA GEM object
+ * @gem_obj: GEM object to free
+ *
+ * This function frees the backing memory of the CMA GEM object, cleans up the
+ * GEM object state and frees the memory used to store the object itself.
+ * Drivers using the CMA helpers should set this as their DRM driver's
+ * ->gem_free_object() callback.
  */
 void drm_gem_cma_free_object(struct drm_gem_object *gem_obj)
 {
        struct drm_gem_cma_object *cma_obj;
 
-       drm_gem_free_mmap_offset(gem_obj);
-
        cma_obj = to_drm_gem_cma_obj(gem_obj);
 
        if (cma_obj->vaddr) {
@@ -170,18 +202,26 @@ void drm_gem_cma_free_object(struct drm_gem_object *gem_obj)
 }
 EXPORT_SYMBOL_GPL(drm_gem_cma_free_object);
 
-/*
- * drm_gem_cma_dumb_create - (struct drm_driver)->dumb_create callback
- * function
+/**
+ * drm_gem_cma_dumb_create_internal - create a dumb buffer object
+ * @file_priv: DRM file-private structure to create the dumb buffer for
+ * @drm: DRM device
+ * @args: IOCTL data
+ *
+ * This aligns the pitch and size arguments to the minimum required. This is
+ * an internal helper that can be wrapped by a driver to account for hardware
+ * with more specific alignment requirements. It should not be used directly
+ * as the ->dumb_create() callback in a DRM driver.
  *
- * This aligns the pitch and size arguments to the minimum required. wrap
- * this into your own function if you need bigger alignment.
+ * Returns:
+ * 0 on success or a negative error code on failure.
  */
-int drm_gem_cma_dumb_create(struct drm_file *file_priv,
-               struct drm_device *dev, struct drm_mode_create_dumb *args)
+int drm_gem_cma_dumb_create_internal(struct drm_file *file_priv,
+                                    struct drm_device *drm,
+                                    struct drm_mode_create_dumb *args)
 {
+       unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
        struct drm_gem_cma_object *cma_obj;
-       int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
 
        if (args->pitch < min_pitch)
                args->pitch = min_pitch;
@@ -189,18 +229,63 @@ int drm_gem_cma_dumb_create(struct drm_file *file_priv,
        if (args->size < args->pitch * args->height)
                args->size = args->pitch * args->height;
 
-       cma_obj = drm_gem_cma_create_with_handle(file_priv, dev,
-                       args->size, &args->handle);
+       cma_obj = drm_gem_cma_create_with_handle(file_priv, drm, args->size,
+                                                &args->handle);
+       return PTR_ERR_OR_ZERO(cma_obj);
+}
+EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_create_internal);
+
+/**
+ * drm_gem_cma_dumb_create - create a dumb buffer object
+ * @file_priv: DRM file-private structure to create the dumb buffer for
+ * @drm: DRM device
+ * @args: IOCTL data
+ *
+ * This function computes the pitch of the dumb buffer and rounds it up to an
+ * integer number of bytes per pixel. Drivers for hardware that doesn't have
+ * any additional restrictions on the pitch can directly use this function as
+ * their ->dumb_create() callback.
+ *
+ * For hardware with additional restrictions, drivers can adjust the fields
+ * set up by userspace and pass the IOCTL data along to the
+ * drm_gem_cma_dumb_create_internal() function.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int drm_gem_cma_dumb_create(struct drm_file *file_priv,
+                           struct drm_device *drm,
+                           struct drm_mode_create_dumb *args)
+{
+       struct drm_gem_cma_object *cma_obj;
+
+       args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+       args->size = args->pitch * args->height;
+
+       cma_obj = drm_gem_cma_create_with_handle(file_priv, drm, args->size,
+                                                &args->handle);
        return PTR_ERR_OR_ZERO(cma_obj);
 }
 EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_create);
 
-/*
- * drm_gem_cma_dumb_map_offset - (struct drm_driver)->dumb_map_offset callback
- * function
+/**
+ * drm_gem_cma_dumb_map_offset - return the fake mmap offset for a CMA GEM
+ *     object
+ * @file_priv: DRM file-private structure containing the GEM object
+ * @drm: DRM device
+ * @handle: GEM object handle
+ * @offset: return location for the fake mmap offset
+ *
+ * This function look up an object by its handle and returns the fake mmap
+ * offset associated with it. Drivers using the CMA helpers should set this
+ * as their DRM driver's ->dumb_map_offset() callback.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
  */
 int drm_gem_cma_dumb_map_offset(struct drm_file *file_priv,
-               struct drm_device *drm, uint32_t handle, uint64_t *offset)
+                               struct drm_device *drm, u32 handle,
+                               u64 *offset)
 {
        struct drm_gem_object *gem_obj;
 
@@ -208,7 +293,7 @@ int drm_gem_cma_dumb_map_offset(struct drm_file *file_priv,
 
        gem_obj = drm_gem_object_lookup(drm, file_priv, handle);
        if (!gem_obj) {
-               dev_err(drm->dev, "failed to lookup gem object\n");
+               dev_err(drm->dev, "failed to lookup GEM object\n");
                mutex_unlock(&drm->struct_mutex);
                return -EINVAL;
        }
@@ -251,8 +336,20 @@ static int drm_gem_cma_mmap_obj(struct drm_gem_cma_object *cma_obj,
        return ret;
 }
 
-/*
- * drm_gem_cma_mmap - (struct file_operation)->mmap callback function
+/**
+ * drm_gem_cma_mmap - memory-map a CMA GEM object
+ * @filp: file object
+ * @vma: VMA for the area to be mapped
+ *
+ * This function implements an augmented version of the GEM DRM file mmap
+ * operation for CMA objects: In addition to the usual GEM VMA setup it
+ * immediately faults in the entire object instead of using on-demaind
+ * faulting. Drivers which employ the CMA helpers should use this function
+ * as their ->mmap() handler in the DRM device file's file_operations
+ * structure.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
  */
 int drm_gem_cma_mmap(struct file *filp, struct vm_area_struct *vma)
 {
@@ -272,7 +369,16 @@ int drm_gem_cma_mmap(struct file *filp, struct vm_area_struct *vma)
 EXPORT_SYMBOL_GPL(drm_gem_cma_mmap);
 
 #ifdef CONFIG_DEBUG_FS
-void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, struct seq_file *m)
+/**
+ * drm_gem_cma_describe - describe a CMA GEM object for debugfs
+ * @cma_obj: CMA GEM object
+ * @m: debugfs file handle
+ *
+ * This function can be used to dump a human-readable representation of the
+ * CMA GEM object into a synthetic file.
+ */
+void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj,
+                         struct seq_file *m)
 {
        struct drm_gem_object *obj = &cma_obj->base;
        struct drm_device *dev = obj->dev;
@@ -291,7 +397,18 @@ void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, struct seq_file *m
 EXPORT_SYMBOL_GPL(drm_gem_cma_describe);
 #endif
 
-/* low-level interface prime helpers */
+/**
+ * drm_gem_cma_prime_get_sg_table - provide a scatter/gather table of pinned
+ *     pages for a CMA GEM object
+ * @obj: GEM object
+ *
+ * This function exports a scatter/gather table suitable for PRIME usage by
+ * calling the standard DMA mapping API. Drivers using the CMA helpers should
+ * set this as their DRM driver's ->gem_prime_get_sg_table() callback.
+ *
+ * Returns:
+ * A pointer to the scatter/gather table of pinned pages or NULL on failure.
+ */
 struct sg_table *drm_gem_cma_prime_get_sg_table(struct drm_gem_object *obj)
 {
        struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(obj);
@@ -315,6 +432,23 @@ out:
 }
 EXPORT_SYMBOL_GPL(drm_gem_cma_prime_get_sg_table);
 
+/**
+ * drm_gem_cma_prime_import_sg_table - produce a CMA GEM object from another
+ *     driver's scatter/gather table of pinned pages
+ * @dev: device to import into
+ * @attach: DMA-BUF attachment
+ * @sgt: scatter/gather table of pinned pages
+ *
+ * This function imports a scatter/gather table exported via DMA-BUF by
+ * another driver. Imported buffers must be physically contiguous in memory
+ * (i.e. the scatter/gather table must contain a single entry). Drivers that
+ * use the CMA helpers should set this as their DRM driver's
+ * ->gem_prime_import_sg_table() callback.
+ *
+ * Returns:
+ * A pointer to a newly created GEM object or an ERR_PTR-encoded negative
+ * error code on failure.
+ */
 struct drm_gem_object *
 drm_gem_cma_prime_import_sg_table(struct drm_device *dev,
                                  struct dma_buf_attachment *attach,
@@ -339,6 +473,18 @@ drm_gem_cma_prime_import_sg_table(struct drm_device *dev,
 }
 EXPORT_SYMBOL_GPL(drm_gem_cma_prime_import_sg_table);
 
+/**
+ * drm_gem_cma_prime_mmap - memory-map an exported CMA GEM object
+ * @obj: GEM object
+ * @vma: VMA for the area to be mapped
+ *
+ * This function maps a buffer imported via DRM PRIME into a userspace
+ * process's address space. Drivers that use the CMA helpers should set this
+ * as their DRM driver's ->gem_prime_mmap() callback.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
 int drm_gem_cma_prime_mmap(struct drm_gem_object *obj,
                           struct vm_area_struct *vma)
 {
@@ -357,6 +503,20 @@ int drm_gem_cma_prime_mmap(struct drm_gem_object *obj,
 }
 EXPORT_SYMBOL_GPL(drm_gem_cma_prime_mmap);
 
+/**
+ * drm_gem_cma_prime_vmap - map a CMA GEM object into the kernel's virtual
+ *     address space
+ * @obj: GEM object
+ *
+ * This function maps a buffer exported via DRM PRIME into the kernel's
+ * virtual address space. Since the CMA buffers are already mapped into the
+ * kernel virtual address space this simply returns the cached virtual
+ * address. Drivers using the CMA helpers should set this as their DRM
+ * driver's ->gem_prime_vmap() callback.
+ *
+ * Returns:
+ * The kernel virtual address of the CMA GEM object's backing store.
+ */
 void *drm_gem_cma_prime_vmap(struct drm_gem_object *obj)
 {
        struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(obj);
@@ -365,6 +525,17 @@ void *drm_gem_cma_prime_vmap(struct drm_gem_object *obj)
 }
 EXPORT_SYMBOL_GPL(drm_gem_cma_prime_vmap);
 
+/**
+ * drm_gem_cma_prime_vunmap - unmap a CMA GEM object from the kernel's virtual
+ *     address space
+ * @obj: GEM object
+ * @vaddr: kernel virtual address where the CMA GEM object was mapped
+ *
+ * This function removes a buffer exported via DRM PRIME from the kernel's
+ * virtual address space. This is a no-op because CMA buffers cannot be
+ * unmapped from kernel space. Drivers using the CMA helpers should set this
+ * as their DRM driver's ->gem_prime_vunmap() callback.
+ */
 void drm_gem_cma_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
 {
        /* Nothing to do */
index 3e6b582f60dd1251e563bb232eb05c1d78f21488..0e47df4ef24efa2226de1f1fa8b4ea26c76e55cb 100644 (file)
@@ -1029,7 +1029,8 @@ void drm_vblank_put(struct drm_device *dev, int crtc)
 {
        struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
 
-       BUG_ON(atomic_read(&vblank->refcount) == 0);
+       if (WARN_ON(atomic_read(&vblank->refcount) == 0))
+               return;
 
        if (WARN_ON(crtc >= dev->num_crtcs))
                return;
index eb6dfe52cab24e1aa36ef12ee951c7c2d7103d6f..c0644bb865f257f9321f30870bd814bc804b2326 100644 (file)
 
 #include <video/mipi_display.h>
 
+/**
+ * DOC: dsi helpers
+ *
+ * These functions contain some common logic and helpers to deal with MIPI DSI
+ * peripherals.
+ *
+ * Helpers are provided for a number of standard MIPI DSI command as well as a
+ * subset of the MIPI DCS command set.
+ */
+
 static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv)
 {
        return of_driver_match_device(dev, drv);
@@ -57,6 +67,29 @@ static struct bus_type mipi_dsi_bus_type = {
        .pm = &mipi_dsi_device_pm_ops,
 };
 
+static int of_device_match(struct device *dev, void *data)
+{
+       return dev->of_node == data;
+}
+
+/**
+ * of_find_mipi_dsi_device_by_node() - find the MIPI DSI device matching a
+ *    device tree node
+ * @np: device tree node
+ *
+ * Return: A pointer to the MIPI DSI device corresponding to @np or NULL if no
+ *    such device exists (or has not been registered yet).
+ */
+struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np)
+{
+       struct device *dev;
+
+       dev = bus_find_device(&mipi_dsi_bus_type, NULL, np, of_device_match);
+
+       return dev ? to_mipi_dsi_device(dev) : NULL;
+}
+EXPORT_SYMBOL(of_find_mipi_dsi_device_by_node);
+
 static void mipi_dsi_dev_release(struct device *dev)
 {
        struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
@@ -198,59 +231,351 @@ int mipi_dsi_detach(struct mipi_dsi_device *dsi)
 }
 EXPORT_SYMBOL(mipi_dsi_detach);
 
+static ssize_t mipi_dsi_device_transfer(struct mipi_dsi_device *dsi,
+                                       struct mipi_dsi_msg *msg)
+{
+       const struct mipi_dsi_host_ops *ops = dsi->host->ops;
+
+       if (!ops || !ops->transfer)
+               return -ENOSYS;
+
+       if (dsi->mode_flags & MIPI_DSI_MODE_LPM)
+               msg->flags |= MIPI_DSI_MSG_USE_LPM;
+
+       return ops->transfer(dsi->host, msg);
+}
+
 /**
- * mipi_dsi_dcs_write - send DCS write command
- * @dsi: DSI device
- * @data: pointer to the command followed by parameters
- * @len: length of @data
+ * mipi_dsi_packet_format_is_short - check if a packet is of the short format
+ * @type: MIPI DSI data type of the packet
+ *
+ * Return: true if the packet for the given data type is a short packet, false
+ * otherwise.
  */
-ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data,
-                           size_t len)
+bool mipi_dsi_packet_format_is_short(u8 type)
+{
+       switch (type) {
+       case MIPI_DSI_V_SYNC_START:
+       case MIPI_DSI_V_SYNC_END:
+       case MIPI_DSI_H_SYNC_START:
+       case MIPI_DSI_H_SYNC_END:
+       case MIPI_DSI_END_OF_TRANSMISSION:
+       case MIPI_DSI_COLOR_MODE_OFF:
+       case MIPI_DSI_COLOR_MODE_ON:
+       case MIPI_DSI_SHUTDOWN_PERIPHERAL:
+       case MIPI_DSI_TURN_ON_PERIPHERAL:
+       case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
+       case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
+       case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
+       case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
+       case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
+       case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
+       case MIPI_DSI_DCS_SHORT_WRITE:
+       case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+       case MIPI_DSI_DCS_READ:
+       case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
+               return true;
+       }
+
+       return false;
+}
+EXPORT_SYMBOL(mipi_dsi_packet_format_is_short);
+
+/**
+ * mipi_dsi_packet_format_is_long - check if a packet is of the long format
+ * @type: MIPI DSI data type of the packet
+ *
+ * Return: true if the packet for the given data type is a long packet, false
+ * otherwise.
+ */
+bool mipi_dsi_packet_format_is_long(u8 type)
+{
+       switch (type) {
+       case MIPI_DSI_NULL_PACKET:
+       case MIPI_DSI_BLANKING_PACKET:
+       case MIPI_DSI_GENERIC_LONG_WRITE:
+       case MIPI_DSI_DCS_LONG_WRITE:
+       case MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20:
+       case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24:
+       case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16:
+       case MIPI_DSI_PACKED_PIXEL_STREAM_30:
+       case MIPI_DSI_PACKED_PIXEL_STREAM_36:
+       case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12:
+       case MIPI_DSI_PACKED_PIXEL_STREAM_16:
+       case MIPI_DSI_PACKED_PIXEL_STREAM_18:
+       case MIPI_DSI_PIXEL_STREAM_3BYTE_18:
+       case MIPI_DSI_PACKED_PIXEL_STREAM_24:
+               return true;
+       }
+
+       return false;
+}
+EXPORT_SYMBOL(mipi_dsi_packet_format_is_long);
+
+/**
+ * mipi_dsi_create_packet - create a packet from a message according to the
+ *     DSI protocol
+ * @packet: pointer to a DSI packet structure
+ * @msg: message to translate into a packet
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
+                          const struct mipi_dsi_msg *msg)
+{
+       const u8 *tx = msg->tx_buf;
+
+       if (!packet || !msg)
+               return -EINVAL;
+
+       /* do some minimum sanity checking */
+       if (!mipi_dsi_packet_format_is_short(msg->type) &&
+           !mipi_dsi_packet_format_is_long(msg->type))
+               return -EINVAL;
+
+       if (msg->channel > 3)
+               return -EINVAL;
+
+       memset(packet, 0, sizeof(*packet));
+       packet->header[0] = ((msg->channel & 0x3) << 6) | (msg->type & 0x3f);
+
+       /* TODO: compute ECC if hardware support is not available */
+
+       /*
+        * Long write packets contain the word count in header bytes 1 and 2.
+        * The payload follows the header and is word count bytes long.
+        *
+        * Short write packets encode up to two parameters in header bytes 1
+        * and 2.
+        */
+       if (mipi_dsi_packet_format_is_long(msg->type)) {
+               packet->header[1] = (msg->tx_len >> 0) & 0xff;
+               packet->header[2] = (msg->tx_len >> 8) & 0xff;
+
+               packet->payload_length = msg->tx_len;
+               packet->payload = tx;
+       } else {
+               packet->header[1] = (msg->tx_len > 0) ? tx[0] : 0;
+               packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0;
+       }
+
+       packet->size = sizeof(packet->header) + packet->payload_length;
+
+       return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_create_packet);
+
+/*
+ * mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of the
+ *    the payload in a long packet transmitted from the peripheral back to the
+ *    host processor
+ * @dsi: DSI peripheral device
+ * @value: the maximum size of the payload
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
+                                           u16 value)
+{
+       u8 tx[2] = { value & 0xff, value >> 8 };
+       struct mipi_dsi_msg msg = {
+               .channel = dsi->channel,
+               .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
+               .tx_len = sizeof(tx),
+               .tx_buf = tx,
+       };
+
+       return mipi_dsi_device_transfer(dsi, &msg);
+}
+EXPORT_SYMBOL(mipi_dsi_set_maximum_return_packet_size);
+
+/**
+ * mipi_dsi_generic_write() - transmit data using a generic write packet
+ * @dsi: DSI peripheral device
+ * @payload: buffer containing the payload
+ * @size: size of payload buffer
+ *
+ * This function will automatically choose the right data type depending on
+ * the payload length.
+ *
+ * Return: The number of bytes transmitted on success or a negative error code
+ * on failure.
+ */
+ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload,
+                              size_t size)
+{
+       struct mipi_dsi_msg msg = {
+               .channel = dsi->channel,
+               .tx_buf = payload,
+               .tx_len = size
+       };
+
+       switch (size) {
+       case 0:
+               msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM;
+               break;
+
+       case 1:
+               msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM;
+               break;
+
+       case 2:
+               msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM;
+               break;
+
+       default:
+               msg.type = MIPI_DSI_GENERIC_LONG_WRITE;
+               break;
+       }
+
+       return mipi_dsi_device_transfer(dsi, &msg);
+}
+EXPORT_SYMBOL(mipi_dsi_generic_write);
+
+/**
+ * mipi_dsi_generic_read() - receive data using a generic read packet
+ * @dsi: DSI peripheral device
+ * @params: buffer containing the request parameters
+ * @num_params: number of request parameters
+ * @data: buffer in which to return the received data
+ * @size: size of receive buffer
+ *
+ * This function will automatically choose the right data type depending on
+ * the number of parameters passed in.
+ *
+ * Return: The number of bytes successfully read or a negative error code on
+ * failure.
+ */
+ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
+                             size_t num_params, void *data, size_t size)
+{
+       struct mipi_dsi_msg msg = {
+               .channel = dsi->channel,
+               .tx_len = num_params,
+               .tx_buf = params,
+               .rx_len = size,
+               .rx_buf = data
+       };
+
+       switch (num_params) {
+       case 0:
+               msg.type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM;
+               break;
+
+       case 1:
+               msg.type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM;
+               break;
+
+       case 2:
+               msg.type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return mipi_dsi_device_transfer(dsi, &msg);
+}
+EXPORT_SYMBOL(mipi_dsi_generic_read);
+
+/**
+ * mipi_dsi_dcs_write_buffer() - transmit a DCS command with payload
+ * @dsi: DSI peripheral device
+ * @data: buffer containing data to be transmitted
+ * @len: size of transmission buffer
+ *
+ * This function will automatically choose the right data type depending on
+ * the command payload length.
+ *
+ * Return: The number of bytes successfully transmitted or a negative error
+ * code on failure.
+ */
+ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi,
+                                 const void *data, size_t len)
 {
-       const struct mipi_dsi_host_ops *ops = dsi->host->ops;
        struct mipi_dsi_msg msg = {
                .channel = dsi->channel,
                .tx_buf = data,
                .tx_len = len
        };
 
-       if (!ops || !ops->transfer)
-               return -ENOSYS;
-
        switch (len) {
        case 0:
                return -EINVAL;
+
        case 1:
                msg.type = MIPI_DSI_DCS_SHORT_WRITE;
                break;
+
        case 2:
                msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
                break;
+
        default:
                msg.type = MIPI_DSI_DCS_LONG_WRITE;
                break;
        }
 
-       if (dsi->mode_flags & MIPI_DSI_MODE_LPM)
-               msg.flags = MIPI_DSI_MSG_USE_LPM;
+       return mipi_dsi_device_transfer(dsi, &msg);
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_write_buffer);
 
-       return ops->transfer(dsi->host, &msg);
+/**
+ * mipi_dsi_dcs_write() - send DCS write command
+ * @dsi: DSI peripheral device
+ * @cmd: DCS command
+ * @data: buffer containing the command payload
+ * @len: command payload length
+ *
+ * This function will automatically choose the right data type depending on
+ * the command payload length.
+ *
+ * Return: The number of bytes successfully transmitted or a negative error
+ * code on failure.
+ */
+ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
+                          const void *data, size_t len)
+{
+       ssize_t err;
+       size_t size;
+       u8 *tx;
+
+       if (len > 0) {
+               size = 1 + len;
+
+               tx = kmalloc(size, GFP_KERNEL);
+               if (!tx)
+                       return -ENOMEM;
+
+               /* concatenate the DCS command byte and the payload */
+               tx[0] = cmd;
+               memcpy(&tx[1], data, len);
+       } else {
+               tx = &cmd;
+               size = 1;
+       }
+
+       err = mipi_dsi_dcs_write_buffer(dsi, tx, size);
+
+       if (len > 0)
+               kfree(tx);
+
+       return err;
 }
 EXPORT_SYMBOL(mipi_dsi_dcs_write);
 
 /**
- * mipi_dsi_dcs_read - send DCS read request command
- * @dsi: DSI device
- * @cmd: DCS read command
- * @data: pointer to read buffer
- * @len: length of @data
+ * mipi_dsi_dcs_read() - send DCS read request command
+ * @dsi: DSI peripheral device
+ * @cmd: DCS command
+ * @data: buffer in which to receive data
+ * @len: size of receive buffer
  *
- * Function returns number of read bytes or error code.
+ * Return: The number of bytes read or a negative error code on failure.
  */
 ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data,
                          size_t len)
 {
-       const struct mipi_dsi_host_ops *ops = dsi->host->ops;
        struct mipi_dsi_msg msg = {
                .channel = dsi->channel,
                .type = MIPI_DSI_DCS_READ,
@@ -260,15 +585,282 @@ ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data,
                .rx_len = len
        };
 
-       if (!ops || !ops->transfer)
-               return -ENOSYS;
+       return mipi_dsi_device_transfer(dsi, &msg);
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_read);
 
-       if (dsi->mode_flags & MIPI_DSI_MODE_LPM)
-               msg.flags = MIPI_DSI_MSG_USE_LPM;
+/**
+ * mipi_dsi_dcs_nop() - send DCS nop packet
+ * @dsi: DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi)
+{
+       ssize_t err;
+
+       err = mipi_dsi_dcs_write(dsi, MIPI_DCS_NOP, NULL, 0);
+       if (err < 0)
+               return err;
 
-       return ops->transfer(dsi->host, &msg);
+       return 0;
 }
-EXPORT_SYMBOL(mipi_dsi_dcs_read);
+EXPORT_SYMBOL(mipi_dsi_dcs_nop);
+
+/**
+ * mipi_dsi_dcs_soft_reset() - perform a software reset of the display module
+ * @dsi: DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi)
+{
+       ssize_t err;
+
+       err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SOFT_RESET, NULL, 0);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_soft_reset);
+
+/**
+ * mipi_dsi_dcs_get_power_mode() - query the display module's current power
+ *    mode
+ * @dsi: DSI peripheral device
+ * @mode: return location for the current power mode
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode)
+{
+       ssize_t err;
+
+       err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_POWER_MODE, mode,
+                               sizeof(*mode));
+       if (err <= 0) {
+               if (err == 0)
+                       err = -ENODATA;
+
+               return err;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_get_power_mode);
+
+/**
+ * mipi_dsi_dcs_get_pixel_format() - gets the pixel format for the RGB image
+ *    data used by the interface
+ * @dsi: DSI peripheral device
+ * @format: return location for the pixel format
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format)
+{
+       ssize_t err;
+
+       err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_PIXEL_FORMAT, format,
+                               sizeof(*format));
+       if (err <= 0) {
+               if (err == 0)
+                       err = -ENODATA;
+
+               return err;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_get_pixel_format);
+
+/**
+ * mipi_dsi_dcs_enter_sleep_mode() - disable all unnecessary blocks inside the
+ *    display module except interface communication
+ * @dsi: DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_enter_sleep_mode(struct mipi_dsi_device *dsi)
+{
+       ssize_t err;
+
+       err = mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_enter_sleep_mode);
+
+/**
+ * mipi_dsi_dcs_exit_sleep_mode() - enable all blocks inside the display
+ *    module
+ * @dsi: DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi)
+{
+       ssize_t err;
+
+       err = mipi_dsi_dcs_write(dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_exit_sleep_mode);
+
+/**
+ * mipi_dsi_dcs_set_display_off() - stop displaying the image data on the
+ *    display device
+ * @dsi: DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_display_off(struct mipi_dsi_device *dsi)
+{
+       ssize_t err;
+
+       err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_set_display_off);
+
+/**
+ * mipi_dsi_dcs_set_display_on() - start displaying the image data on the
+ *    display device
+ * @dsi: DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure
+ */
+int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi)
+{
+       ssize_t err;
+
+       err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_set_display_on);
+
+/**
+ * mipi_dsi_dcs_set_column_address() - define the column extent of the frame
+ *    memory accessed by the host processor
+ * @dsi: DSI peripheral device
+ * @start: first column of frame memory
+ * @end: last column of frame memory
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start,
+                                   u16 end)
+{
+       u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff };
+       ssize_t err;
+
+       err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_COLUMN_ADDRESS, payload,
+                                sizeof(payload));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_set_column_address);
+
+/**
+ * mipi_dsi_dcs_set_page_address() - define the page extent of the frame
+ *    memory accessed by the host processor
+ * @dsi: DSI peripheral device
+ * @start: first page of frame memory
+ * @end: last page of frame memory
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start,
+                                 u16 end)
+{
+       u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff };
+       ssize_t err;
+
+       err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PAGE_ADDRESS, payload,
+                                sizeof(payload));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_set_page_address);
+
+/**
+ * mipi_dsi_dcs_set_tear_off() - turn off the display module's Tearing Effect
+ *    output signal on the TE signal line
+ * @dsi: DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure
+ */
+int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi)
+{
+       ssize_t err;
+
+       err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_OFF, NULL, 0);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_off);
+
+/**
+ * mipi_dsi_dcs_set_tear_on() - turn on the display module's Tearing Effect
+ *    output signal on the TE signal line.
+ * @dsi: DSI peripheral device
+ * @mode: the Tearing Effect Output Line mode
+ *
+ * Return: 0 on success or a negative error code on failure
+ */
+int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi,
+                            enum mipi_dsi_dcs_tear_mode mode)
+{
+       u8 value = mode;
+       ssize_t err;
+
+       err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, &value,
+                                sizeof(value));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_on);
+
+/**
+ * mipi_dsi_dcs_set_pixel_format() - sets the pixel format for the RGB image
+ *    data used by the interface
+ * @dsi: DSI peripheral device
+ * @format: pixel format
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format)
+{
+       ssize_t err;
+
+       err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format,
+                                sizeof(format));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_set_pixel_format);
 
 static int mipi_dsi_drv_probe(struct device *dev)
 {
@@ -295,12 +887,18 @@ static void mipi_dsi_drv_shutdown(struct device *dev)
 }
 
 /**
- * mipi_dsi_driver_register - register a driver for DSI devices
+ * mipi_dsi_driver_register_full() - register a driver for DSI devices
  * @drv: DSI driver structure
+ * @owner: owner module
+ *
+ * Return: 0 on success or a negative error code on failure.
  */
-int mipi_dsi_driver_register(struct mipi_dsi_driver *drv)
+int mipi_dsi_driver_register_full(struct mipi_dsi_driver *drv,
+                                 struct module *owner)
 {
        drv->driver.bus = &mipi_dsi_bus_type;
+       drv->driver.owner = owner;
+
        if (drv->probe)
                drv->driver.probe = mipi_dsi_drv_probe;
        if (drv->remove)
@@ -310,11 +908,13 @@ int mipi_dsi_driver_register(struct mipi_dsi_driver *drv)
 
        return driver_register(&drv->driver);
 }
-EXPORT_SYMBOL(mipi_dsi_driver_register);
+EXPORT_SYMBOL(mipi_dsi_driver_register_full);
 
 /**
- * mipi_dsi_driver_unregister - unregister a driver for DSI devices
+ * mipi_dsi_driver_unregister() - unregister a driver for DSI devices
  * @drv: DSI driver structure
+ *
+ * Return: 0 on success or a negative error code on failure.
  */
 void mipi_dsi_driver_unregister(struct mipi_dsi_driver *drv)
 {
index 474e4d12a2d8a73109a35fe3eb3b9948635fedaa..51cc47d827d82f09f1ed9d0e4200e299b4fa628c 100644 (file)
@@ -157,14 +157,20 @@ void drm_modeset_unlock_all(struct drm_device *dev)
 EXPORT_SYMBOL(drm_modeset_unlock_all);
 
 /**
- * drm_modeset_lock_crtc - lock crtc with hidden acquire ctx
- * @crtc: drm crtc
+ * drm_modeset_lock_crtc - lock crtc with hidden acquire ctx for a plane update
+ * @crtc: DRM CRTC
+ * @plane: DRM plane to be updated on @crtc
+ *
+ * This function locks the given crtc and plane (which should be either the
+ * primary or cursor plane) using a hidden acquire context. This is necessary so
+ * that drivers internally using the atomic interfaces can grab further locks
+ * with the lock acquire context.
  *
- * This function locks the given crtc using a hidden acquire context. This is
- * necessary so that drivers internally using the atomic interfaces can grab
- * further locks with the lock acquire context.
+ * Note that @plane can be NULL, e.g. when the cursor support hasn't yet been
+ * converted to universal planes yet.
  */
-void drm_modeset_lock_crtc(struct drm_crtc *crtc)
+void drm_modeset_lock_crtc(struct drm_crtc *crtc,
+                          struct drm_plane *plane)
 {
        struct drm_modeset_acquire_ctx *ctx;
        int ret;
@@ -180,6 +186,18 @@ retry:
        if (ret)
                goto fail;
 
+       if (plane) {
+               ret = drm_modeset_lock(&plane->mutex, ctx);
+               if (ret)
+                       goto fail;
+
+               if (plane->crtc) {
+                       ret = drm_modeset_lock(&plane->crtc->mutex, ctx);
+                       if (ret)
+                               goto fail;
+               }
+       }
+
        WARN_ON(crtc->acquire_ctx);
 
        /* now we hold the locks, so now that it is safe, stash the
@@ -437,15 +455,14 @@ void drm_modeset_unlock(struct drm_modeset_lock *lock)
 }
 EXPORT_SYMBOL(drm_modeset_unlock);
 
-/* Temporary.. until we have sufficiently fine grained locking, there
- * are a couple scenarios where it is convenient to grab all crtc locks.
- * It is planned to remove this:
- */
+/* In some legacy codepaths it's convenient to just grab all the crtc and plane
+ * related locks. */
 int drm_modeset_lock_all_crtcs(struct drm_device *dev,
                struct drm_modeset_acquire_ctx *ctx)
 {
        struct drm_mode_config *config = &dev->mode_config;
        struct drm_crtc *crtc;
+       struct drm_plane *plane;
        int ret = 0;
 
        list_for_each_entry(crtc, &config->crtc_list, head) {
@@ -454,6 +471,12 @@ int drm_modeset_lock_all_crtcs(struct drm_device *dev,
                        return ret;
        }
 
+       list_for_each_entry(plane, &config->plane_list, head) {
+               ret = drm_modeset_lock(&plane->mutex, ctx);
+               if (ret)
+                       return ret;
+       }
+
        return 0;
 }
 EXPORT_SYMBOL(drm_modeset_lock_all_crtcs);
index 93c6533c25daf61c1d2ca3f6067a54c9af5f4bea..18a1ac6ac22f396aa55b34187b7fb89a9392613b 100644 (file)
@@ -443,7 +443,7 @@ int drm_plane_helper_commit(struct drm_plane *plane,
                        crtc_funcs[i]->atomic_begin(crtc[i]);
        }
 
-       plane_funcs->atomic_update(plane);
+       plane_funcs->atomic_update(plane, plane_state);
 
        for (i = 0; i < 2; i++) {
                if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush)
index 6872eca6555e4e2fb833a74f86e746eb77c23372..7482b06cd08fc60f35da2099ed0d3ed88cf11802 100644 (file)
@@ -669,7 +669,7 @@ int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
  * the driver is responsible for mapping the pages into the
  * importers address space for use with dma_buf itself.
  */
-struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages)
+struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages)
 {
        struct sg_table *sg = NULL;
        int ret;
index 6adb1e5cfb086499537ea786a13e709da87a59ec..34d46aa75416aaa024e8aec4bb5867c570f3e3fb 100644 (file)
 #include <drm/drm_panel.h>
 #include <drm/bridge/ptn3460.h>
 
-#include "exynos_drm_drv.h"
 #include "exynos_dp_core.h"
 
 #define ctx_from_connector(c)  container_of(c, struct exynos_dp_device, \
                                        connector)
 
+static inline struct exynos_dp_device *
+display_to_dp(struct exynos_drm_display *d)
+{
+       return container_of(d, struct exynos_dp_device, display);
+}
+
 struct bridge_init {
        struct i2c_client *client;
        struct device_node *node;
@@ -882,7 +887,7 @@ static void exynos_dp_hotplug(struct work_struct *work)
 
 static void exynos_dp_commit(struct exynos_drm_display *display)
 {
-       struct exynos_dp_device *dp = display->ctx;
+       struct exynos_dp_device *dp = display_to_dp(display);
        int ret;
 
        /* Keep the panel disabled while we configure video */
@@ -1020,7 +1025,7 @@ static int exynos_drm_attach_lcd_bridge(struct drm_device *dev,
 static int exynos_dp_create_connector(struct exynos_drm_display *display,
                                struct drm_encoder *encoder)
 {
-       struct exynos_dp_device *dp = display->ctx;
+       struct exynos_dp_device *dp = display_to_dp(display);
        struct drm_connector *connector = &dp->connector;
        int ret;
 
@@ -1052,33 +1057,19 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display,
 
 static void exynos_dp_phy_init(struct exynos_dp_device *dp)
 {
-       if (dp->phy) {
+       if (dp->phy)
                phy_power_on(dp->phy);
-       } else if (dp->phy_addr) {
-               u32 reg;
-
-               reg = __raw_readl(dp->phy_addr);
-               reg |= dp->enable_mask;
-               __raw_writel(reg, dp->phy_addr);
-       }
 }
 
 static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
 {
-       if (dp->phy) {
+       if (dp->phy)
                phy_power_off(dp->phy);
-       } else if (dp->phy_addr) {
-               u32 reg;
-
-               reg = __raw_readl(dp->phy_addr);
-               reg &= ~(dp->enable_mask);
-               __raw_writel(reg, dp->phy_addr);
-       }
 }
 
 static void exynos_dp_poweron(struct exynos_drm_display *display)
 {
-       struct exynos_dp_device *dp = display->ctx;
+       struct exynos_dp_device *dp = display_to_dp(display);
 
        if (dp->dpms_mode == DRM_MODE_DPMS_ON)
                return;
@@ -1099,7 +1090,7 @@ static void exynos_dp_poweron(struct exynos_drm_display *display)
 
 static void exynos_dp_poweroff(struct exynos_drm_display *display)
 {
-       struct exynos_dp_device *dp = display->ctx;
+       struct exynos_dp_device *dp = display_to_dp(display);
 
        if (dp->dpms_mode != DRM_MODE_DPMS_ON)
                return;
@@ -1124,7 +1115,7 @@ static void exynos_dp_poweroff(struct exynos_drm_display *display)
 
 static void exynos_dp_dpms(struct exynos_drm_display *display, int mode)
 {
-       struct exynos_dp_device *dp = display->ctx;
+       struct exynos_dp_device *dp = display_to_dp(display);
 
        switch (mode) {
        case DRM_MODE_DPMS_ON:
@@ -1147,11 +1138,6 @@ static struct exynos_drm_display_ops exynos_dp_display_ops = {
        .commit = exynos_dp_commit,
 };
 
-static struct exynos_drm_display exynos_dp_display = {
-       .type = EXYNOS_DISPLAY_TYPE_LCD,
-       .ops = &exynos_dp_display_ops,
-};
-
 static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev)
 {
        struct device_node *dp_node = dev->of_node;
@@ -1210,44 +1196,6 @@ static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev)
        return dp_video_config;
 }
 
-static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
-{
-       struct device_node *dp_phy_node = of_node_get(dp->dev->of_node);
-       u32 phy_base;
-       int ret = 0;
-
-       dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy");
-       if (!dp_phy_node) {
-               dp->phy = devm_phy_get(dp->dev, "dp");
-               return PTR_ERR_OR_ZERO(dp->phy);
-       }
-
-       if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) {
-               dev_err(dp->dev, "failed to get reg for dptx-phy\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       if (of_property_read_u32(dp_phy_node, "samsung,enable-mask",
-                               &dp->enable_mask)) {
-               dev_err(dp->dev, "failed to get enable-mask for dptx-phy\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       dp->phy_addr = ioremap(phy_base, SZ_4);
-       if (!dp->phy_addr) {
-               dev_err(dp->dev, "failed to ioremap dp-phy\n");
-               ret = -ENOMEM;
-               goto err;
-       }
-
-err:
-       of_node_put(dp_phy_node);
-
-       return ret;
-}
-
 static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
 {
        int ret;
@@ -1263,10 +1211,10 @@ static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
 
 static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 {
+       struct exynos_dp_device *dp = dev_get_drvdata(dev);
        struct platform_device *pdev = to_platform_device(dev);
        struct drm_device *drm_dev = data;
        struct resource *res;
-       struct exynos_dp_device *dp = exynos_dp_display.ctx;
        unsigned int irq_flags;
        int ret = 0;
 
@@ -1277,9 +1225,21 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
        if (IS_ERR(dp->video_info))
                return PTR_ERR(dp->video_info);
 
-       ret = exynos_dp_dt_parse_phydata(dp);
-       if (ret)
-               return ret;
+       dp->phy = devm_phy_get(dp->dev, "dp");
+       if (IS_ERR(dp->phy)) {
+               dev_err(dp->dev, "no DP phy configured\n");
+               ret = PTR_ERR(dp->phy);
+               if (ret) {
+                       /*
+                        * phy itself is not enabled, so we can move forward
+                        * assigning NULL to phy pointer.
+                        */
+                       if (ret == -ENOSYS || ret == -ENODEV)
+                               dp->phy = NULL;
+                       else
+                               return ret;
+               }
+       }
 
        if (!dp->panel) {
                ret = exynos_dp_dt_parse_panel(dp);
@@ -1346,17 +1306,15 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 
        dp->drm_dev = drm_dev;
 
-       platform_set_drvdata(pdev, &exynos_dp_display);
-
-       return exynos_drm_create_enc_conn(drm_dev, &exynos_dp_display);
+       return exynos_drm_create_enc_conn(drm_dev, &dp->display);
 }
 
 static void exynos_dp_unbind(struct device *dev, struct device *master,
                                void *data)
 {
-       struct exynos_drm_display *display = dev_get_drvdata(dev);
+       struct exynos_dp_device *dp = dev_get_drvdata(dev);
 
-       exynos_dp_dpms(display, DRM_MODE_DPMS_OFF);
+       exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_OFF);
 }
 
 static const struct component_ops exynos_dp_ops = {
@@ -1371,16 +1329,20 @@ static int exynos_dp_probe(struct platform_device *pdev)
        struct exynos_dp_device *dp;
        int ret;
 
-       ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
-                                       exynos_dp_display.type);
-       if (ret)
-               return ret;
-
        dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
                                GFP_KERNEL);
        if (!dp)
                return -ENOMEM;
 
+       dp->display.type = EXYNOS_DISPLAY_TYPE_LCD;
+       dp->display.ops = &exynos_dp_display_ops;
+       platform_set_drvdata(pdev, dp);
+
+       ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
+                                       dp->display.type);
+       if (ret)
+               return ret;
+
        panel_node = of_parse_phandle(dev->of_node, "panel", 0);
        if (panel_node) {
                dp->panel = of_drm_find_panel(panel_node);
@@ -1389,8 +1351,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
                        return -EPROBE_DEFER;
        }
 
-       exynos_dp_display.ctx = dp;
-
        ret = component_add(&pdev->dev, &exynos_dp_ops);
        if (ret)
                exynos_drm_component_del(&pdev->dev,
@@ -1410,19 +1370,17 @@ static int exynos_dp_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int exynos_dp_suspend(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct exynos_drm_display *display = platform_get_drvdata(pdev);
+       struct exynos_dp_device *dp = dev_get_drvdata(dev);
 
-       exynos_dp_dpms(display, DRM_MODE_DPMS_OFF);
+       exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_OFF);
        return 0;
 }
 
 static int exynos_dp_resume(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct exynos_drm_display *display = platform_get_drvdata(pdev);
+       struct exynos_dp_device *dp = dev_get_drvdata(dev);
 
-       exynos_dp_dpms(display, DRM_MODE_DPMS_ON);
+       exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_ON);
        return 0;
 }
 #endif
index a1aee6931bd74afb54928b3b40be150a4dba8483..164f171168e7ef175d9d726e1f1ca231c8da2e49 100644 (file)
@@ -17,6 +17,8 @@
 #include <drm/drm_dp_helper.h>
 #include <drm/exynos_drm.h>
 
+#include "exynos_drm_drv.h"
+
 #define DP_TIMEOUT_LOOP_COUNT 100
 #define MAX_CR_LOOP 5
 #define MAX_EQ_LOOP 5
@@ -145,6 +147,7 @@ struct link_train {
 };
 
 struct exynos_dp_device {
+       struct exynos_drm_display display;
        struct device           *dev;
        struct drm_device       *drm_dev;
        struct drm_connector    connector;
@@ -153,8 +156,6 @@ struct exynos_dp_device {
        struct clk              *clock;
        unsigned int            irq;
        void __iomem            *reg_base;
-       void __iomem            *phy_addr;
-       unsigned int            enable_mask;
 
        struct video_info       *video_info;
        struct link_train       link_train;
index 690dcddab725658528aa3936298204db206c317c..e353d353836fe87d3f8151de6559db24a9fe70a5 100644 (file)
 #ifndef _EXYNOS_DRM_CRTC_H_
 #define _EXYNOS_DRM_CRTC_H_
 
-struct drm_device;
-struct drm_crtc;
-struct exynos_drm_manager;
-struct exynos_drm_overlay;
+#include "exynos_drm_drv.h"
 
 int exynos_drm_crtc_create(struct exynos_drm_manager *manager);
 int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe);
index 3dc678ed9949241737d1b0055044040d704439dd..37678cf4425ad515eaac8a6c244cd53a5ced3c5e 100644 (file)
@@ -22,6 +22,7 @@
 #include "exynos_drm_drv.h"
 
 struct exynos_dpi {
+       struct exynos_drm_display display;
        struct device *dev;
        struct device_node *panel_node;
 
@@ -35,6 +36,11 @@ struct exynos_dpi {
 
 #define connector_to_dpi(c) container_of(c, struct exynos_dpi, connector)
 
+static inline struct exynos_dpi *display_to_dpi(struct exynos_drm_display *d)
+{
+       return container_of(d, struct exynos_dpi, display);
+}
+
 static enum drm_connector_status
 exynos_dpi_detect(struct drm_connector *connector, bool force)
 {
@@ -100,7 +106,7 @@ static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = {
 static int exynos_dpi_create_connector(struct exynos_drm_display *display,
                                       struct drm_encoder *encoder)
 {
-       struct exynos_dpi *ctx = display->ctx;
+       struct exynos_dpi *ctx = display_to_dpi(display);
        struct drm_connector *connector = &ctx->connector;
        int ret;
 
@@ -141,7 +147,7 @@ static void exynos_dpi_poweroff(struct exynos_dpi *ctx)
 
 static void exynos_dpi_dpms(struct exynos_drm_display *display, int mode)
 {
-       struct exynos_dpi *ctx = display->ctx;
+       struct exynos_dpi *ctx = display_to_dpi(display);
 
        switch (mode) {
        case DRM_MODE_DPMS_ON:
@@ -165,11 +171,6 @@ static struct exynos_drm_display_ops exynos_dpi_display_ops = {
        .dpms = exynos_dpi_dpms
 };
 
-static struct exynos_drm_display exynos_dpi_display = {
-       .type = EXYNOS_DISPLAY_TYPE_LCD,
-       .ops = &exynos_dpi_display_ops,
-};
-
 /* of_* functions will be removed after merge of of_graph patches */
 static struct device_node *
 of_get_child_by_name_reg(struct device_node *parent, const char *name, u32 reg)
@@ -299,20 +300,21 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev)
        struct exynos_dpi *ctx;
        int ret;
 
-       ret = exynos_drm_component_add(dev,
-                                       EXYNOS_DEVICE_TYPE_CONNECTOR,
-                                       exynos_dpi_display.type);
-       if (ret)
-               return ERR_PTR(ret);
-
        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
-               goto err_del_component;
+               return ERR_PTR(-ENOMEM);
 
+       ctx->display.type = EXYNOS_DISPLAY_TYPE_LCD;
+       ctx->display.ops = &exynos_dpi_display_ops;
        ctx->dev = dev;
-       exynos_dpi_display.ctx = ctx;
        ctx->dpms_mode = DRM_MODE_DPMS_OFF;
 
+       ret = exynos_drm_component_add(dev,
+                                       EXYNOS_DEVICE_TYPE_CONNECTOR,
+                                       ctx->display.type);
+       if (ret)
+               return ERR_PTR(ret);
+
        ret = exynos_dpi_parse_dt(ctx);
        if (ret < 0) {
                devm_kfree(dev, ctx);
@@ -328,7 +330,7 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev)
                }
        }
 
-       return &exynos_dpi_display;
+       return &ctx->display;
 
 err_del_component:
        exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
@@ -336,16 +338,16 @@ err_del_component:
        return NULL;
 }
 
-int exynos_dpi_remove(struct device *dev)
+int exynos_dpi_remove(struct exynos_drm_display *display)
 {
-       struct exynos_dpi *ctx = exynos_dpi_display.ctx;
+       struct exynos_dpi *ctx = display_to_dpi(display);
 
-       exynos_dpi_dpms(&exynos_dpi_display, DRM_MODE_DPMS_OFF);
+       exynos_dpi_dpms(&ctx->display, DRM_MODE_DPMS_OFF);
 
        if (ctx->panel)
                drm_panel_detach(ctx->panel);
 
-       exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
+       exynos_drm_component_del(ctx->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
 
        return 0;
 }
index e5c4c6c8c967066dc05f9964544520e9273a6d0a..25ba3628960a3511460b156d1cf264a8eac72ce5 100644 (file)
@@ -203,8 +203,6 @@ static int exynos_drm_resume(struct drm_device *dev)
        }
        drm_modeset_unlock_all(dev);
 
-       drm_helper_resume_force_mode(dev);
-
        return 0;
 }
 
@@ -475,8 +473,6 @@ void exynos_drm_component_del(struct device *dev,
                        list_del(&cdev->list);
                        kfree(cdev);
                }
-
-               break;
        }
 
        mutex_unlock(&drm_component_lock);
@@ -556,182 +552,68 @@ static const struct component_master_ops exynos_drm_ops = {
        .unbind         = exynos_drm_unbind,
 };
 
-static int exynos_drm_platform_probe(struct platform_device *pdev)
-{
-       struct component_match *match;
-       int ret;
-
-       pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-       exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls);
-
+static struct platform_driver *const exynos_drm_kms_drivers[] = {
 #ifdef CONFIG_DRM_EXYNOS_FIMD
-       ret = platform_driver_register(&fimd_driver);
-       if (ret < 0)
-               return ret;
+       &fimd_driver,
 #endif
-
 #ifdef CONFIG_DRM_EXYNOS_DP
-       ret = platform_driver_register(&dp_driver);
-       if (ret < 0)
-               goto err_unregister_fimd_drv;
+       &dp_driver,
 #endif
-
 #ifdef CONFIG_DRM_EXYNOS_DSI
-       ret = platform_driver_register(&dsi_driver);
-       if (ret < 0)
-               goto err_unregister_dp_drv;
+       &dsi_driver,
 #endif
-
 #ifdef CONFIG_DRM_EXYNOS_HDMI
-       ret = platform_driver_register(&mixer_driver);
-       if (ret < 0)
-               goto err_unregister_dsi_drv;
-       ret = platform_driver_register(&hdmi_driver);
-       if (ret < 0)
-               goto err_unregister_mixer_drv;
+       &mixer_driver,
+       &hdmi_driver,
 #endif
+};
 
-       match = exynos_drm_match_add(&pdev->dev);
-       if (IS_ERR(match)) {
-               ret = PTR_ERR(match);
-               goto err_unregister_hdmi_drv;
-       }
-
-       ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops,
-                                               match);
-       if (ret < 0)
-               goto err_unregister_hdmi_drv;
-
+static struct platform_driver *const exynos_drm_non_kms_drivers[] = {
 #ifdef CONFIG_DRM_EXYNOS_G2D
-       ret = platform_driver_register(&g2d_driver);
-       if (ret < 0)
-               goto err_del_component_master;
+       &g2d_driver,
 #endif
-
 #ifdef CONFIG_DRM_EXYNOS_FIMC
-       ret = platform_driver_register(&fimc_driver);
-       if (ret < 0)
-               goto err_unregister_g2d_drv;
+       &fimc_driver,
 #endif
-
 #ifdef CONFIG_DRM_EXYNOS_ROTATOR
-       ret = platform_driver_register(&rotator_driver);
-       if (ret < 0)
-               goto err_unregister_fimc_drv;
+       &rotator_driver,
 #endif
-
 #ifdef CONFIG_DRM_EXYNOS_GSC
-       ret = platform_driver_register(&gsc_driver);
-       if (ret < 0)
-               goto err_unregister_rotator_drv;
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_IPP
-       ret = platform_driver_register(&ipp_driver);
-       if (ret < 0)
-               goto err_unregister_gsc_drv;
-
-       ret = exynos_platform_device_ipp_register();
-       if (ret < 0)
-               goto err_unregister_ipp_drv;
+       &gsc_driver,
 #endif
-
-       return ret;
-
 #ifdef CONFIG_DRM_EXYNOS_IPP
-err_unregister_ipp_drv:
-       platform_driver_unregister(&ipp_driver);
-err_unregister_gsc_drv:
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_GSC
-       platform_driver_unregister(&gsc_driver);
-err_unregister_rotator_drv:
+       &ipp_driver,
 #endif
+};
 
-#ifdef CONFIG_DRM_EXYNOS_ROTATOR
-       platform_driver_unregister(&rotator_driver);
-err_unregister_fimc_drv:
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_FIMC
-       platform_driver_unregister(&fimc_driver);
-err_unregister_g2d_drv:
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_G2D
-       platform_driver_unregister(&g2d_driver);
-err_del_component_master:
-#endif
-       component_master_del(&pdev->dev, &exynos_drm_ops);
-
-err_unregister_hdmi_drv:
-#ifdef CONFIG_DRM_EXYNOS_HDMI
-       platform_driver_unregister(&hdmi_driver);
-err_unregister_mixer_drv:
-       platform_driver_unregister(&mixer_driver);
-err_unregister_dsi_drv:
-#endif
+static int exynos_drm_platform_probe(struct platform_device *pdev)
+{
+       struct component_match *match;
 
-#ifdef CONFIG_DRM_EXYNOS_DSI
-       platform_driver_unregister(&dsi_driver);
-err_unregister_dp_drv:
-#endif
+       pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+       exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls);
 
-#ifdef CONFIG_DRM_EXYNOS_DP
-       platform_driver_unregister(&dp_driver);
-err_unregister_fimd_drv:
-#endif
+       match = exynos_drm_match_add(&pdev->dev);
+       if (IS_ERR(match)) {
+               return PTR_ERR(match);
+       }
 
-#ifdef CONFIG_DRM_EXYNOS_FIMD
-       platform_driver_unregister(&fimd_driver);
-#endif
-       return ret;
+       return component_master_add_with_match(&pdev->dev, &exynos_drm_ops,
+                                              match);
 }
 
 static int exynos_drm_platform_remove(struct platform_device *pdev)
 {
-#ifdef CONFIG_DRM_EXYNOS_IPP
-       exynos_platform_device_ipp_unregister();
-       platform_driver_unregister(&ipp_driver);
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_GSC
-       platform_driver_unregister(&gsc_driver);
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_ROTATOR
-       platform_driver_unregister(&rotator_driver);
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_FIMC
-       platform_driver_unregister(&fimc_driver);
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_G2D
-       platform_driver_unregister(&g2d_driver);
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_HDMI
-       platform_driver_unregister(&mixer_driver);
-       platform_driver_unregister(&hdmi_driver);
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_FIMD
-       platform_driver_unregister(&fimd_driver);
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_DSI
-       platform_driver_unregister(&dsi_driver);
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_DP
-       platform_driver_unregister(&dp_driver);
-#endif
        component_master_del(&pdev->dev, &exynos_drm_ops);
        return 0;
 }
 
+static const char * const strings[] = {
+       "samsung,exynos3",
+       "samsung,exynos4",
+       "samsung,exynos5",
+};
+
 static struct platform_driver exynos_drm_platform_driver = {
        .probe  = exynos_drm_platform_probe,
        .remove = exynos_drm_platform_remove,
@@ -744,7 +626,25 @@ static struct platform_driver exynos_drm_platform_driver = {
 
 static int exynos_drm_init(void)
 {
-       int ret;
+       bool is_exynos = false;
+       int ret, i, j;
+
+       /*
+        * Register device object only in case of Exynos SoC.
+        *
+        * Below codes resolves temporarily infinite loop issue incurred
+        * by Exynos drm driver when using multi-platform kernel.
+        * So these codes will be replaced with more generic way later.
+        */
+       for (i = 0; i < ARRAY_SIZE(strings); i++) {
+               if (of_machine_is_compatible(strings[i])) {
+                       is_exynos = true;
+                       break;
+               }
+       }
+
+       if (!is_exynos)
+               return -ENODEV;
 
        /*
         * Register device object only in case of Exynos SoC.
@@ -763,24 +663,50 @@ static int exynos_drm_init(void)
        if (IS_ERR(exynos_drm_pdev))
                return PTR_ERR(exynos_drm_pdev);
 
-#ifdef CONFIG_DRM_EXYNOS_VIDI
        ret = exynos_drm_probe_vidi();
        if (ret < 0)
                goto err_unregister_pd;
+
+       for (i = 0; i < ARRAY_SIZE(exynos_drm_kms_drivers); ++i) {
+               ret = platform_driver_register(exynos_drm_kms_drivers[i]);
+               if (ret < 0)
+                       goto err_unregister_kms_drivers;
+       }
+
+       for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) {
+               ret = platform_driver_register(exynos_drm_non_kms_drivers[j]);
+               if (ret < 0)
+                       goto err_unregister_non_kms_drivers;
+       }
+
+#ifdef CONFIG_DRM_EXYNOS_IPP
+       ret = exynos_platform_device_ipp_register();
+       if (ret < 0)
+               goto err_unregister_non_kms_drivers;
 #endif
 
        ret = platform_driver_register(&exynos_drm_platform_driver);
        if (ret)
-               goto err_remove_vidi;
+               goto err_unregister_resources;
 
        return 0;
 
-err_remove_vidi:
-#ifdef CONFIG_DRM_EXYNOS_VIDI
+err_unregister_resources:
+#ifdef CONFIG_DRM_EXYNOS_IPP
+       exynos_platform_device_ipp_unregister();
+#endif
+
+err_unregister_non_kms_drivers:
+       while (--j >= 0)
+               platform_driver_unregister(exynos_drm_non_kms_drivers[j]);
+
+err_unregister_kms_drivers:
+       while (--i >= 0)
+               platform_driver_unregister(exynos_drm_kms_drivers[i]);
+
        exynos_drm_remove_vidi();
 
 err_unregister_pd:
-#endif
        platform_device_unregister(exynos_drm_pdev);
 
        return ret;
@@ -788,10 +714,22 @@ err_unregister_pd:
 
 static void exynos_drm_exit(void)
 {
+       int i;
+
+#ifdef CONFIG_DRM_EXYNOS_IPP
+       exynos_platform_device_ipp_unregister();
+#endif
+
+       for (i = ARRAY_SIZE(exynos_drm_non_kms_drivers) - 1; i >= 0; --i)
+               platform_driver_unregister(exynos_drm_non_kms_drivers[i]);
+
+       for (i = ARRAY_SIZE(exynos_drm_kms_drivers) - 1; i >= 0; --i)
+               platform_driver_unregister(exynos_drm_kms_drivers[i]);
+
        platform_driver_unregister(&exynos_drm_platform_driver);
-#ifdef CONFIG_DRM_EXYNOS_VIDI
+
        exynos_drm_remove_vidi();
-#endif
+
        platform_device_unregister(exynos_drm_pdev);
 }
 
index d22e640f59a012c0b2e26d3d325c3a6154ec26c5..2e5063488c5026ccd99e717d7e132289ca187dee 100644 (file)
@@ -15,6 +15,7 @@
 #ifndef _EXYNOS_DRM_DRV_H_
 #define _EXYNOS_DRM_DRV_H_
 
+#include <drm/drmP.h>
 #include <linux/module.h>
 
 #define MAX_CRTC       3
 #define MAX_FB_BUFFER  4
 #define DEFAULT_ZPOS   -1
 
-#define _wait_for(COND, MS) ({ \
-       unsigned long timeout__ = jiffies + msecs_to_jiffies(MS);       \
-       int ret__ = 0;                                                  \
-       while (!(COND)) {                                               \
-               if (time_after(jiffies, timeout__)) {                   \
-                       ret__ = -ETIMEDOUT;                             \
-                       break;                                          \
-               }                                                       \
-       }                                                               \
-       ret__;                                                          \
-})
-
-#define wait_for(COND, MS) _wait_for(COND, MS)
-
-struct drm_device;
-struct exynos_drm_overlay;
-struct drm_connector;
-
 /* This enumerates device type. */
 enum exynos_drm_device_type {
        EXYNOS_DEVICE_TYPE_NONE,
@@ -83,10 +66,10 @@ enum exynos_drm_output_type {
  * @dma_addr: array of bus(accessed by dma) address to the memory region
  *           allocated for a overlay.
  * @zpos: order of overlay layer(z position).
- * @default_win: a window to be enabled.
- * @color_key: color key on or off.
  * @index_color: if using color key feature then this value would be used
  *                     as index color.
+ * @default_win: a window to be enabled.
+ * @color_key: color key on or off.
  * @local_path: in case of lcd type, local path mode on or off.
  * @transparency: transparency on or off.
  * @activated: activated or not.
@@ -114,19 +97,20 @@ struct exynos_drm_overlay {
        uint32_t pixel_format;
        dma_addr_t dma_addr[MAX_FB_BUFFER];
        int zpos;
-
-       bool default_win;
-       bool color_key;
        unsigned int index_color;
-       bool local_path;
-       bool transparency;
-       bool activated;
+
+       bool default_win:1;
+       bool color_key:1;
+       bool local_path:1;
+       bool transparency:1;
+       bool activated:1;
 };
 
 /*
  * Exynos DRM Display Structure.
  *     - this structure is common to analog tv, digital tv and lcd panel.
  *
+ * @create_connector: initialize and register a new connector
  * @remove: cleans up the display for removal
  * @mode_fixup: fix mode data comparing to hw specific display mode.
  * @mode_set: convert drm_display_mode to hw specific display mode and
@@ -168,7 +152,6 @@ struct exynos_drm_display {
        struct drm_encoder *encoder;
        struct drm_connector *connector;
        struct exynos_drm_display_ops *ops;
-       void *ctx;
 };
 
 /*
@@ -227,7 +210,6 @@ struct exynos_drm_manager {
        struct drm_crtc *crtc;
        int pipe;
        struct exynos_drm_manager_ops *ops;
-       void *ctx;
 };
 
 struct exynos_drm_g2d_private {
@@ -279,8 +261,6 @@ struct exynos_drm_private {
  * @dev: pointer to device object for subdrv device driver.
  * @drm_dev: pointer to drm_device and this pointer would be set
  *     when sub driver calls exynos_drm_subdrv_register().
- * @manager: subdrv has its own manager to control a hardware appropriately
- *     and we can access a hardware drawing on this manager.
  * @probe: this callback would be called by exynos drm driver after
  *     subdrv is registered to it.
  * @remove: this callback is used to release resources created
@@ -312,45 +292,34 @@ int exynos_drm_device_subdrv_remove(struct drm_device *dev);
 int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file);
 void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
 
-/*
- * this function registers exynos drm hdmi platform device. It ensures only one
- * instance of the device is created.
- */
-int exynos_platform_device_hdmi_register(void);
-
-/*
- * this function unregisters exynos drm hdmi platform device if it exists.
- */
-void exynos_platform_device_hdmi_unregister(void);
-
-/*
- * this function registers exynos drm ipp platform device.
- */
+#ifdef CONFIG_DRM_EXYNOS_IPP
 int exynos_platform_device_ipp_register(void);
-
-/*
- * this function unregisters exynos drm ipp platform device if it exists.
- */
 void exynos_platform_device_ipp_unregister(void);
+#else
+static inline int exynos_platform_device_ipp_register(void) { return 0; }
+static inline void exynos_platform_device_ipp_unregister(void) {}
+#endif
+
 
 #ifdef CONFIG_DRM_EXYNOS_DPI
 struct exynos_drm_display * exynos_dpi_probe(struct device *dev);
-int exynos_dpi_remove(struct device *dev);
+int exynos_dpi_remove(struct exynos_drm_display *display);
 #else
 static inline struct exynos_drm_display *
 exynos_dpi_probe(struct device *dev) { return NULL; }
-static inline int exynos_dpi_remove(struct device *dev) { return 0; }
+static inline int exynos_dpi_remove(struct exynos_drm_display *display)
+{
+       return 0;
+}
 #endif
 
-/*
- * this function registers exynos drm vidi platform device/driver.
- */
+#ifdef CONFIG_DRM_EXYNOS_VIDI
 int exynos_drm_probe_vidi(void);
-
-/*
- * this function unregister exynos drm vidi platform device/driver.
- */
 void exynos_drm_remove_vidi(void);
+#else
+static inline int exynos_drm_probe_vidi(void) { return 0; }
+static inline void exynos_drm_remove_vidi(void) {}
+#endif
 
 /* This function creates a encoder and a connector, and initializes them. */
 int exynos_drm_create_enc_conn(struct drm_device *dev,
index acf7e9e39dcd86e11590d7398ee136a9f81d8a60..05fe93dc57a8bccdd14b6db9cb40f9ef99944619 100644 (file)
@@ -268,9 +268,9 @@ struct exynos_dsi_driver_data {
 };
 
 struct exynos_dsi {
+       struct exynos_drm_display display;
        struct mipi_dsi_host dsi_host;
        struct drm_connector connector;
-       struct drm_encoder *encoder;
        struct device_node *panel_node;
        struct drm_panel *panel;
        struct device *dev;
@@ -304,6 +304,11 @@ struct exynos_dsi {
 #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
 #define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector)
 
+static inline struct exynos_dsi *display_to_dsi(struct exynos_drm_display *d)
+{
+       return container_of(d, struct exynos_dsi, display);
+}
+
 static struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
        .plltmr_reg = 0x50,
        .has_freqband = 1,
@@ -316,6 +321,11 @@ static struct exynos_dsi_driver_data exynos4_dsi_driver_data = {
        .has_clklane_stop = 1,
 };
 
+static struct exynos_dsi_driver_data exynos4415_dsi_driver_data = {
+       .plltmr_reg = 0x58,
+       .has_clklane_stop = 1,
+};
+
 static struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
        .plltmr_reg = 0x58,
 };
@@ -325,6 +335,8 @@ static struct of_device_id exynos_dsi_of_match[] = {
          .data = &exynos3_dsi_driver_data },
        { .compatible = "samsung,exynos4210-mipi-dsi",
          .data = &exynos4_dsi_driver_data },
+       { .compatible = "samsung,exynos4415-mipi-dsi",
+         .data = &exynos4415_dsi_driver_data },
        { .compatible = "samsung,exynos5410-mipi-dsi",
          .data = &exynos5_dsi_driver_data },
        { }
@@ -1104,7 +1116,7 @@ static irqreturn_t exynos_dsi_irq(int irq, void *dev_id)
 static irqreturn_t exynos_dsi_te_irq_handler(int irq, void *dev_id)
 {
        struct exynos_dsi *dsi = (struct exynos_dsi *)dev_id;
-       struct drm_encoder *encoder = dsi->encoder;
+       struct drm_encoder *encoder = dsi->display.encoder;
 
        if (dsi->state & DSIM_STATE_ENABLED)
                exynos_drm_crtc_te_handler(encoder->crtc);
@@ -1143,6 +1155,7 @@ static int exynos_dsi_init(struct exynos_dsi *dsi)
 static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi)
 {
        int ret;
+       int te_gpio_irq;
 
        dsi->te_gpio = of_get_named_gpio(dsi->panel_node, "te-gpios", 0);
        if (!gpio_is_valid(dsi->te_gpio)) {
@@ -1157,14 +1170,10 @@ static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi)
                goto out;
        }
 
-       /*
-        * This TE GPIO IRQ should not be set to IRQ_NOAUTOEN, because panel
-        * calls drm_panel_init() first then calls mipi_dsi_attach() in probe().
-        * It means that te_gpio is invalid when exynos_dsi_enable_irq() is
-        * called by drm_panel_init() before panel is attached.
-        */
-       ret = request_threaded_irq(gpio_to_irq(dsi->te_gpio),
-                                       exynos_dsi_te_irq_handler, NULL,
+       te_gpio_irq = gpio_to_irq(dsi->te_gpio);
+
+       irq_set_status_flags(te_gpio_irq, IRQ_NOAUTOEN);
+       ret = request_threaded_irq(te_gpio_irq, exynos_dsi_te_irq_handler, NULL,
                                        IRQF_TRIGGER_RISING, "TE", dsi);
        if (ret) {
                dev_err(dsi->dev, "request interrupt failed with %d\n", ret);
@@ -1195,9 +1204,6 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
        dsi->mode_flags = device->mode_flags;
        dsi->panel_node = device->dev.of_node;
 
-       if (dsi->connector.dev)
-               drm_helper_hpd_irq_event(dsi->connector.dev);
-
        /*
         * This is a temporary solution and should be made by more generic way.
         *
@@ -1211,6 +1217,9 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
                        return ret;
        }
 
+       if (dsi->connector.dev)
+               drm_helper_hpd_irq_event(dsi->connector.dev);
+
        return 0;
 }
 
@@ -1236,7 +1245,7 @@ static bool exynos_dsi_is_short_dsi_type(u8 type)
 }
 
 static ssize_t exynos_dsi_host_transfer(struct mipi_dsi_host *host,
-                                      struct mipi_dsi_msg *msg)
+                                       const struct mipi_dsi_msg *msg)
 {
        struct exynos_dsi *dsi = host_to_dsi(host);
        struct exynos_dsi_transfer xfer;
@@ -1369,16 +1378,17 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi)
        exynos_dsi_set_display_mode(dsi);
        exynos_dsi_set_display_enable(dsi, true);
 
+       dsi->state |= DSIM_STATE_ENABLED;
+
        ret = drm_panel_enable(dsi->panel);
        if (ret < 0) {
+               dsi->state &= ~DSIM_STATE_ENABLED;
                exynos_dsi_set_display_enable(dsi, false);
                drm_panel_unprepare(dsi->panel);
                exynos_dsi_poweroff(dsi);
                return ret;
        }
 
-       dsi->state |= DSIM_STATE_ENABLED;
-
        return 0;
 }
 
@@ -1397,7 +1407,7 @@ static void exynos_dsi_disable(struct exynos_dsi *dsi)
 
 static void exynos_dsi_dpms(struct exynos_drm_display *display, int mode)
 {
-       struct exynos_dsi *dsi = display->ctx;
+       struct exynos_dsi *dsi = display_to_dsi(display);
 
        if (dsi->panel) {
                switch (mode) {
@@ -1474,7 +1484,7 @@ exynos_dsi_best_encoder(struct drm_connector *connector)
 {
        struct exynos_dsi *dsi = connector_to_dsi(connector);
 
-       return dsi->encoder;
+       return dsi->display.encoder;
 }
 
 static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
@@ -1486,12 +1496,10 @@ static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
 static int exynos_dsi_create_connector(struct exynos_drm_display *display,
                                       struct drm_encoder *encoder)
 {
-       struct exynos_dsi *dsi = display->ctx;
+       struct exynos_dsi *dsi = display_to_dsi(display);
        struct drm_connector *connector = &dsi->connector;
        int ret;
 
-       dsi->encoder = encoder;
-
        connector->polled = DRM_CONNECTOR_POLL_HPD;
 
        ret = drm_connector_init(encoder->dev, connector,
@@ -1512,7 +1520,7 @@ static int exynos_dsi_create_connector(struct exynos_drm_display *display,
 static void exynos_dsi_mode_set(struct exynos_drm_display *display,
                         struct drm_display_mode *mode)
 {
-       struct exynos_dsi *dsi = display->ctx;
+       struct exynos_dsi *dsi = display_to_dsi(display);
        struct videomode *vm = &dsi->vm;
 
        vm->hactive = mode->hdisplay;
@@ -1531,10 +1539,6 @@ static struct exynos_drm_display_ops exynos_dsi_display_ops = {
        .dpms = exynos_dsi_dpms
 };
 
-static struct exynos_drm_display exynos_dsi_display = {
-       .type = EXYNOS_DISPLAY_TYPE_LCD,
-       .ops = &exynos_dsi_display_ops,
-};
 MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
 
 /* of_* functions will be removed after merge of of_graph patches */
@@ -1640,28 +1644,28 @@ end:
 static int exynos_dsi_bind(struct device *dev, struct device *master,
                                void *data)
 {
+       struct exynos_drm_display *display = dev_get_drvdata(dev);
+       struct exynos_dsi *dsi = display_to_dsi(display);
        struct drm_device *drm_dev = data;
-       struct exynos_dsi *dsi;
        int ret;
 
-       ret = exynos_drm_create_enc_conn(drm_dev, &exynos_dsi_display);
+       ret = exynos_drm_create_enc_conn(drm_dev, display);
        if (ret) {
                DRM_ERROR("Encoder create [%d] failed with %d\n",
-                               exynos_dsi_display.type, ret);
+                         display->type, ret);
                return ret;
        }
 
-       dsi = exynos_dsi_display.ctx;
-
        return mipi_dsi_host_register(&dsi->dsi_host);
 }
 
 static void exynos_dsi_unbind(struct device *dev, struct device *master,
                                void *data)
 {
-       struct exynos_dsi *dsi = exynos_dsi_display.ctx;
+       struct exynos_drm_display *display = dev_get_drvdata(dev);
+       struct exynos_dsi *dsi = display_to_dsi(display);
 
-       exynos_dsi_dpms(&exynos_dsi_display, DRM_MODE_DPMS_OFF);
+       exynos_dsi_dpms(display, DRM_MODE_DPMS_OFF);
 
        mipi_dsi_host_unregister(&dsi->dsi_host);
 }
@@ -1673,22 +1677,23 @@ static const struct component_ops exynos_dsi_component_ops = {
 
 static int exynos_dsi_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct resource *res;
        struct exynos_dsi *dsi;
        int ret;
 
-       ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
-                                       exynos_dsi_display.type);
+       dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
+       if (!dsi)
+               return -ENOMEM;
+
+       dsi->display.type = EXYNOS_DISPLAY_TYPE_LCD;
+       dsi->display.ops = &exynos_dsi_display_ops;
+
+       ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
+                                      dsi->display.type);
        if (ret)
                return ret;
 
-       dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
-       if (!dsi) {
-               dev_err(&pdev->dev, "failed to allocate dsi object.\n");
-               ret = -ENOMEM;
-               goto err_del_component;
-       }
-
        /* To be checked as invalid one */
        dsi->te_gpio = -ENOENT;
 
@@ -1697,9 +1702,9 @@ static int exynos_dsi_probe(struct platform_device *pdev)
        INIT_LIST_HEAD(&dsi->transfer_list);
 
        dsi->dsi_host.ops = &exynos_dsi_ops;
-       dsi->dsi_host.dev = &pdev->dev;
+       dsi->dsi_host.dev = dev;
 
-       dsi->dev = &pdev->dev;
+       dsi->dev = dev;
        dsi->driver_data = exynos_dsi_get_driver_data(pdev);
 
        ret = exynos_dsi_parse_dt(dsi);
@@ -1708,70 +1713,68 @@ static int exynos_dsi_probe(struct platform_device *pdev)
 
        dsi->supplies[0].supply = "vddcore";
        dsi->supplies[1].supply = "vddio";
-       ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(dsi->supplies),
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dsi->supplies),
                                      dsi->supplies);
        if (ret) {
-               dev_info(&pdev->dev, "failed to get regulators: %d\n", ret);
+               dev_info(dev, "failed to get regulators: %d\n", ret);
                return -EPROBE_DEFER;
        }
 
-       dsi->pll_clk = devm_clk_get(&pdev->dev, "pll_clk");
+       dsi->pll_clk = devm_clk_get(dev, "pll_clk");
        if (IS_ERR(dsi->pll_clk)) {
-               dev_info(&pdev->dev, "failed to get dsi pll input clock\n");
+               dev_info(dev, "failed to get dsi pll input clock\n");
                ret = PTR_ERR(dsi->pll_clk);
                goto err_del_component;
        }
 
-       dsi->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
+       dsi->bus_clk = devm_clk_get(dev, "bus_clk");
        if (IS_ERR(dsi->bus_clk)) {
-               dev_info(&pdev->dev, "failed to get dsi bus clock\n");
+               dev_info(dev, "failed to get dsi bus clock\n");
                ret = PTR_ERR(dsi->bus_clk);
                goto err_del_component;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       dsi->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       dsi->reg_base = devm_ioremap_resource(dev, res);
        if (IS_ERR(dsi->reg_base)) {
-               dev_err(&pdev->dev, "failed to remap io region\n");
+               dev_err(dev, "failed to remap io region\n");
                ret = PTR_ERR(dsi->reg_base);
                goto err_del_component;
        }
 
-       dsi->phy = devm_phy_get(&pdev->dev, "dsim");
+       dsi->phy = devm_phy_get(dev, "dsim");
        if (IS_ERR(dsi->phy)) {
-               dev_info(&pdev->dev, "failed to get dsim phy\n");
+               dev_info(dev, "failed to get dsim phy\n");
                ret = PTR_ERR(dsi->phy);
                goto err_del_component;
        }
 
        dsi->irq = platform_get_irq(pdev, 0);
        if (dsi->irq < 0) {
-               dev_err(&pdev->dev, "failed to request dsi irq resource\n");
+               dev_err(dev, "failed to request dsi irq resource\n");
                ret = dsi->irq;
                goto err_del_component;
        }
 
        irq_set_status_flags(dsi->irq, IRQ_NOAUTOEN);
-       ret = devm_request_threaded_irq(&pdev->dev, dsi->irq, NULL,
+       ret = devm_request_threaded_irq(dev, dsi->irq, NULL,
                                        exynos_dsi_irq, IRQF_ONESHOT,
-                                       dev_name(&pdev->dev), dsi);
+                                       dev_name(dev), dsi);
        if (ret) {
-               dev_err(&pdev->dev, "failed to request dsi irq\n");
+               dev_err(dev, "failed to request dsi irq\n");
                goto err_del_component;
        }
 
-       exynos_dsi_display.ctx = dsi;
-
-       platform_set_drvdata(pdev, &exynos_dsi_display);
+       platform_set_drvdata(pdev, &dsi->display);
 
-       ret = component_add(&pdev->dev, &exynos_dsi_component_ops);
+       ret = component_add(dev, &exynos_dsi_component_ops);
        if (ret)
                goto err_del_component;
 
        return ret;
 
 err_del_component:
-       exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
+       exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
        return ret;
 }
 
index b7a1620a7e79cfff9abff9eec3f283316f524249..26305d8dd93a4a64060ca53609cdec2f1bd77eb4 100644 (file)
@@ -14,8 +14,6 @@
 #ifndef _EXYNOS_DRM_ENCODER_H_
 #define _EXYNOS_DRM_ENCODER_H_
 
-struct exynos_drm_manager;
-
 void exynos_drm_encoder_setup(struct drm_device *dev);
 struct drm_encoder *exynos_drm_encoder_create(struct drm_device *dev,
                        struct exynos_drm_display *mgr,
index 085b066a99934116963b0aa3a1fe6d4a136387c2..e5810d13bf9c5377b9faa5afc0fc333bd6d2ab17 100644 (file)
@@ -84,8 +84,6 @@
 /* FIMD has totally five hardware windows. */
 #define WINDOWS_NR     5
 
-#define get_fimd_manager(mgr)  platform_get_drvdata(to_platform_device(dev))
-
 struct fimd_driver_data {
        unsigned int timing_base;
        unsigned int lcdblk_offset;
@@ -96,6 +94,7 @@ struct fimd_driver_data {
        unsigned int has_clksel:1;
        unsigned int has_limited_fmt:1;
        unsigned int has_vidoutcon:1;
+       unsigned int has_vtsel:1;
 };
 
 static struct fimd_driver_data s3c64xx_fimd_driver_data = {
@@ -118,6 +117,17 @@ static struct fimd_driver_data exynos4_fimd_driver_data = {
        .lcdblk_vt_shift = 10,
        .lcdblk_bypass_shift = 1,
        .has_shadowcon = 1,
+       .has_vtsel = 1,
+};
+
+static struct fimd_driver_data exynos4415_fimd_driver_data = {
+       .timing_base = 0x20000,
+       .lcdblk_offset = 0x210,
+       .lcdblk_vt_shift = 10,
+       .lcdblk_bypass_shift = 1,
+       .has_shadowcon = 1,
+       .has_vidoutcon = 1,
+       .has_vtsel = 1,
 };
 
 static struct fimd_driver_data exynos5_fimd_driver_data = {
@@ -127,6 +137,7 @@ static struct fimd_driver_data exynos5_fimd_driver_data = {
        .lcdblk_bypass_shift = 15,
        .has_shadowcon = 1,
        .has_vidoutcon = 1,
+       .has_vtsel = 1,
 };
 
 struct fimd_win_data {
@@ -146,6 +157,7 @@ struct fimd_win_data {
 };
 
 struct fimd_context {
+       struct exynos_drm_manager       manager;
        struct device                   *dev;
        struct drm_device               *drm_dev;
        struct clk                      *bus_clk;
@@ -173,6 +185,11 @@ struct fimd_context {
        struct exynos_drm_display *display;
 };
 
+static inline struct fimd_context *mgr_to_fimd(struct exynos_drm_manager *mgr)
+{
+       return container_of(mgr, struct fimd_context, manager);
+}
+
 static const struct of_device_id fimd_driver_dt_match[] = {
        { .compatible = "samsung,s3c6400-fimd",
          .data = &s3c64xx_fimd_driver_data },
@@ -180,6 +197,8 @@ static const struct of_device_id fimd_driver_dt_match[] = {
          .data = &exynos3_fimd_driver_data },
        { .compatible = "samsung,exynos4210-fimd",
          .data = &exynos4_fimd_driver_data },
+       { .compatible = "samsung,exynos4415-fimd",
+         .data = &exynos4415_fimd_driver_data },
        { .compatible = "samsung,exynos5250-fimd",
          .data = &exynos5_fimd_driver_data },
        {},
@@ -197,7 +216,7 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data(
 
 static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = mgr_to_fimd(mgr);
 
        if (ctx->suspended)
                return;
@@ -214,9 +233,35 @@ static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
                DRM_DEBUG_KMS("vblank wait timed out.\n");
 }
 
+static void fimd_enable_video_output(struct fimd_context *ctx, int win,
+                                       bool enable)
+{
+       u32 val = readl(ctx->regs + WINCON(win));
+
+       if (enable)
+               val |= WINCONx_ENWIN;
+       else
+               val &= ~WINCONx_ENWIN;
+
+       writel(val, ctx->regs + WINCON(win));
+}
+
+static void fimd_enable_shadow_channel_path(struct fimd_context *ctx, int win,
+                                               bool enable)
+{
+       u32 val = readl(ctx->regs + SHADOWCON);
+
+       if (enable)
+               val |= SHADOWCON_CHx_ENABLE(win);
+       else
+               val &= ~SHADOWCON_CHx_ENABLE(win);
+
+       writel(val, ctx->regs + SHADOWCON);
+}
+
 static void fimd_clear_channel(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = mgr_to_fimd(mgr);
        int win, ch_enabled = 0;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -226,16 +271,12 @@ static void fimd_clear_channel(struct exynos_drm_manager *mgr)
                u32 val = readl(ctx->regs + WINCON(win));
 
                if (val & WINCONx_ENWIN) {
-                       /* wincon */
-                       val &= ~WINCONx_ENWIN;
-                       writel(val, ctx->regs + WINCON(win));
-
-                       /* unprotect windows */
-                       if (ctx->driver_data->has_shadowcon) {
-                               val = readl(ctx->regs + SHADOWCON);
-                               val &= ~SHADOWCON_CHx_ENABLE(win);
-                               writel(val, ctx->regs + SHADOWCON);
-                       }
+                       fimd_enable_video_output(ctx, win, false);
+
+                       if (ctx->driver_data->has_shadowcon)
+                               fimd_enable_shadow_channel_path(ctx, win,
+                                                               false);
+
                        ch_enabled = 1;
                }
        }
@@ -253,7 +294,7 @@ static void fimd_clear_channel(struct exynos_drm_manager *mgr)
 static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
                        struct drm_device *drm_dev)
 {
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = mgr_to_fimd(mgr);
        struct exynos_drm_private *priv;
        priv = drm_dev->dev_private;
 
@@ -275,7 +316,7 @@ static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
 
 static void fimd_mgr_remove(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = mgr_to_fimd(mgr);
 
        /* detach this sub driver from iommu mapping if supported. */
        if (is_drm_iommu_supported(ctx->drm_dev))
@@ -315,14 +356,14 @@ static bool fimd_mode_fixup(struct exynos_drm_manager *mgr,
 static void fimd_mode_set(struct exynos_drm_manager *mgr,
                const struct drm_display_mode *in_mode)
 {
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = mgr_to_fimd(mgr);
 
        drm_mode_copy(&ctx->mode, in_mode);
 }
 
 static void fimd_commit(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = mgr_to_fimd(mgr);
        struct drm_display_mode *mode = &ctx->mode;
        struct fimd_driver_data *driver_data = ctx->driver_data;
        void *timing_base = ctx->regs + driver_data->timing_base;
@@ -343,7 +384,8 @@ static void fimd_commit(struct exynos_drm_manager *mgr)
                writel(0, timing_base + I80IFCONFBx(0));
 
                /* set video type selection to I80 interface */
-               if (ctx->sysreg && regmap_update_bits(ctx->sysreg,
+               if (driver_data->has_vtsel && ctx->sysreg &&
+                               regmap_update_bits(ctx->sysreg,
                                        driver_data->lcdblk_offset,
                                        0x3 << driver_data->lcdblk_vt_shift,
                                        0x1 << driver_data->lcdblk_vt_shift)) {
@@ -421,7 +463,7 @@ static void fimd_commit(struct exynos_drm_manager *mgr)
 
 static int fimd_enable_vblank(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = mgr_to_fimd(mgr);
        u32 val;
 
        if (ctx->suspended)
@@ -431,12 +473,19 @@ static int fimd_enable_vblank(struct exynos_drm_manager *mgr)
                val = readl(ctx->regs + VIDINTCON0);
 
                val |= VIDINTCON0_INT_ENABLE;
-               val |= VIDINTCON0_INT_FRAME;
 
-               val &= ~VIDINTCON0_FRAMESEL0_MASK;
-               val |= VIDINTCON0_FRAMESEL0_VSYNC;
-               val &= ~VIDINTCON0_FRAMESEL1_MASK;
-               val |= VIDINTCON0_FRAMESEL1_NONE;
+               if (ctx->i80_if) {
+                       val |= VIDINTCON0_INT_I80IFDONE;
+                       val |= VIDINTCON0_INT_SYSMAINCON;
+                       val &= ~VIDINTCON0_INT_SYSSUBCON;
+               } else {
+                       val |= VIDINTCON0_INT_FRAME;
+
+                       val &= ~VIDINTCON0_FRAMESEL0_MASK;
+                       val |= VIDINTCON0_FRAMESEL0_VSYNC;
+                       val &= ~VIDINTCON0_FRAMESEL1_MASK;
+                       val |= VIDINTCON0_FRAMESEL1_NONE;
+               }
 
                writel(val, ctx->regs + VIDINTCON0);
        }
@@ -446,7 +495,7 @@ static int fimd_enable_vblank(struct exynos_drm_manager *mgr)
 
 static void fimd_disable_vblank(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = mgr_to_fimd(mgr);
        u32 val;
 
        if (ctx->suspended)
@@ -455,9 +504,15 @@ static void fimd_disable_vblank(struct exynos_drm_manager *mgr)
        if (test_and_clear_bit(0, &ctx->irq_flags)) {
                val = readl(ctx->regs + VIDINTCON0);
 
-               val &= ~VIDINTCON0_INT_FRAME;
                val &= ~VIDINTCON0_INT_ENABLE;
 
+               if (ctx->i80_if) {
+                       val &= ~VIDINTCON0_INT_I80IFDONE;
+                       val &= ~VIDINTCON0_INT_SYSMAINCON;
+                       val &= ~VIDINTCON0_INT_SYSSUBCON;
+               } else
+                       val &= ~VIDINTCON0_INT_FRAME;
+
                writel(val, ctx->regs + VIDINTCON0);
        }
 }
@@ -465,7 +520,7 @@ static void fimd_disable_vblank(struct exynos_drm_manager *mgr)
 static void fimd_win_mode_set(struct exynos_drm_manager *mgr,
                        struct exynos_drm_overlay *overlay)
 {
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = mgr_to_fimd(mgr);
        struct fimd_win_data *win_data;
        int win;
        unsigned long offset;
@@ -623,7 +678,7 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx,
 
 static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos)
 {
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = mgr_to_fimd(mgr);
        struct fimd_win_data *win_data;
        int win = zpos;
        unsigned long val, alpha, size;
@@ -730,20 +785,14 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos)
        if (win != 0)
                fimd_win_set_colkey(ctx, win);
 
-       /* wincon */
-       val = readl(ctx->regs + WINCON(win));
-       val |= WINCONx_ENWIN;
-       writel(val, ctx->regs + WINCON(win));
+       fimd_enable_video_output(ctx, win, true);
+
+       if (ctx->driver_data->has_shadowcon)
+               fimd_enable_shadow_channel_path(ctx, win, true);
 
        /* Enable DMA channel and unprotect windows */
        fimd_shadow_protect_win(ctx, win, false);
 
-       if (ctx->driver_data->has_shadowcon) {
-               val = readl(ctx->regs + SHADOWCON);
-               val |= SHADOWCON_CHx_ENABLE(win);
-               writel(val, ctx->regs + SHADOWCON);
-       }
-
        win_data->enabled = true;
 
        if (ctx->i80_if)
@@ -752,10 +801,9 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos)
 
 static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos)
 {
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = mgr_to_fimd(mgr);
        struct fimd_win_data *win_data;
        int win = zpos;
-       u32 val;
 
        if (win == DEFAULT_ZPOS)
                win = ctx->default_win;
@@ -774,18 +822,12 @@ static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos)
        /* protect windows */
        fimd_shadow_protect_win(ctx, win, true);
 
-       /* wincon */
-       val = readl(ctx->regs + WINCON(win));
-       val &= ~WINCONx_ENWIN;
-       writel(val, ctx->regs + WINCON(win));
+       fimd_enable_video_output(ctx, win, false);
 
-       /* unprotect windows */
-       if (ctx->driver_data->has_shadowcon) {
-               val = readl(ctx->regs + SHADOWCON);
-               val &= ~SHADOWCON_CHx_ENABLE(win);
-               writel(val, ctx->regs + SHADOWCON);
-       }
+       if (ctx->driver_data->has_shadowcon)
+               fimd_enable_shadow_channel_path(ctx, win, false);
 
+       /* unprotect windows */
        fimd_shadow_protect_win(ctx, win, false);
 
        win_data->enabled = false;
@@ -793,7 +835,7 @@ static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos)
 
 static void fimd_window_suspend(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = mgr_to_fimd(mgr);
        struct fimd_win_data *win_data;
        int i;
 
@@ -803,12 +845,11 @@ static void fimd_window_suspend(struct exynos_drm_manager *mgr)
                if (win_data->enabled)
                        fimd_win_disable(mgr, i);
        }
-       fimd_wait_for_vblank(mgr);
 }
 
 static void fimd_window_resume(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = mgr_to_fimd(mgr);
        struct fimd_win_data *win_data;
        int i;
 
@@ -821,7 +862,7 @@ static void fimd_window_resume(struct exynos_drm_manager *mgr)
 
 static void fimd_apply(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = mgr_to_fimd(mgr);
        struct fimd_win_data *win_data;
        int i;
 
@@ -838,7 +879,7 @@ static void fimd_apply(struct exynos_drm_manager *mgr)
 
 static int fimd_poweron(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = mgr_to_fimd(mgr);
        int ret;
 
        if (!ctx->suspended)
@@ -886,7 +927,7 @@ bus_clk_err:
 
 static int fimd_poweroff(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = mgr_to_fimd(mgr);
 
        if (ctx->suspended)
                return 0;
@@ -928,39 +969,41 @@ static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
 
 static void fimd_trigger(struct device *dev)
 {
-       struct exynos_drm_manager *mgr = get_fimd_manager(dev);
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = dev_get_drvdata(dev);
        struct fimd_driver_data *driver_data = ctx->driver_data;
        void *timing_base = ctx->regs + driver_data->timing_base;
        u32 reg;
 
-       atomic_set(&ctx->triggering, 1);
+        /*
+         * Skips triggering if in triggering state, because multiple triggering
+         * requests can cause panel reset.
+         */
+       if (atomic_read(&ctx->triggering))
+               return;
 
-       reg = readl(ctx->regs + VIDINTCON0);
-       reg |= (VIDINTCON0_INT_ENABLE | VIDINTCON0_INT_I80IFDONE |
-                                               VIDINTCON0_INT_SYSMAINCON);
-       writel(reg, ctx->regs + VIDINTCON0);
+       /* Enters triggering mode */
+       atomic_set(&ctx->triggering, 1);
 
        reg = readl(timing_base + TRIGCON);
        reg |= (TRGMODE_I80_RGB_ENABLE_I80 | SWTRGCMD_I80_RGB_ENABLE);
        writel(reg, timing_base + TRIGCON);
+
+       /*
+        * Exits triggering mode if vblank is not enabled yet, because when the
+        * VIDINTCON0 register is not set, it can not exit from triggering mode.
+        */
+       if (!test_bit(0, &ctx->irq_flags))
+               atomic_set(&ctx->triggering, 0);
 }
 
 static void fimd_te_handler(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = mgr_to_fimd(mgr);
 
        /* Checks the crtc is detached already from encoder */
        if (ctx->pipe < 0 || !ctx->drm_dev)
                return;
 
-        /*
-        * Skips to trigger if in triggering state, because multiple triggering
-        * requests can cause panel reset.
-        */
-       if (atomic_read(&ctx->triggering))
-               return;
-
        /*
         * If there is a page flip request, triggers and handles the page flip
         * event so that current fb can be updated into panel GRAM.
@@ -972,10 +1015,10 @@ static void fimd_te_handler(struct exynos_drm_manager *mgr)
        if (atomic_read(&ctx->wait_vsync_event)) {
                atomic_set(&ctx->wait_vsync_event, 0);
                wake_up(&ctx->wait_vsync_queue);
-
-               if (!atomic_read(&ctx->triggering))
-                       drm_handle_vblank(ctx->drm_dev, ctx->pipe);
        }
+
+       if (test_bit(0, &ctx->irq_flags))
+               drm_handle_vblank(ctx->drm_dev, ctx->pipe);
 }
 
 static struct exynos_drm_manager_ops fimd_manager_ops = {
@@ -992,11 +1035,6 @@ static struct exynos_drm_manager_ops fimd_manager_ops = {
        .te_handler = fimd_te_handler,
 };
 
-static struct exynos_drm_manager fimd_manager = {
-       .type = EXYNOS_DISPLAY_TYPE_LCD,
-       .ops = &fimd_manager_ops,
-};
-
 static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
 {
        struct fimd_context *ctx = (struct fimd_context *)dev_id;
@@ -1013,16 +1051,10 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
                goto out;
 
        if (ctx->i80_if) {
-               /* unset I80 frame done interrupt */
-               val = readl(ctx->regs + VIDINTCON0);
-               val &= ~(VIDINTCON0_INT_I80IFDONE | VIDINTCON0_INT_SYSMAINCON);
-               writel(val, ctx->regs + VIDINTCON0);
+               exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
 
-               /* exit triggering mode */
+               /* Exits triggering mode */
                atomic_set(&ctx->triggering, 0);
-
-               drm_handle_vblank(ctx->drm_dev, ctx->pipe);
-               exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
        } else {
                drm_handle_vblank(ctx->drm_dev, ctx->pipe);
                exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
@@ -1040,11 +1072,11 @@ out:
 
 static int fimd_bind(struct device *dev, struct device *master, void *data)
 {
-       struct fimd_context *ctx = fimd_manager.ctx;
+       struct fimd_context *ctx = dev_get_drvdata(dev);
        struct drm_device *drm_dev = data;
 
-       fimd_mgr_initialize(&fimd_manager, drm_dev);
-       exynos_drm_crtc_create(&fimd_manager);
+       fimd_mgr_initialize(&ctx->manager, drm_dev);
+       exynos_drm_crtc_create(&ctx->manager);
        if (ctx->display)
                exynos_drm_create_enc_conn(drm_dev, ctx->display);
 
@@ -1055,15 +1087,14 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
 static void fimd_unbind(struct device *dev, struct device *master,
                        void *data)
 {
-       struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
-       struct fimd_context *ctx = fimd_manager.ctx;
+       struct fimd_context *ctx = dev_get_drvdata(dev);
 
-       fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
+       fimd_dpms(&ctx->manager, DRM_MODE_DPMS_OFF);
 
        if (ctx->display)
-               exynos_dpi_remove(dev);
+               exynos_dpi_remove(ctx->display);
 
-       fimd_mgr_remove(mgr);
+       fimd_mgr_remove(&ctx->manager);
 }
 
 static const struct component_ops fimd_component_ops = {
@@ -1079,21 +1110,20 @@ static int fimd_probe(struct platform_device *pdev)
        struct resource *res;
        int ret = -EINVAL;
 
-       ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
-                                       fimd_manager.type);
-       if (ret)
-               return ret;
-
-       if (!dev->of_node) {
-               ret = -ENODEV;
-               goto err_del_component;
-       }
+       if (!dev->of_node)
+               return -ENODEV;
 
        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
-       if (!ctx) {
-               ret = -ENOMEM;
-               goto err_del_component;
-       }
+       if (!ctx)
+               return -ENOMEM;
+
+       ctx->manager.type = EXYNOS_DISPLAY_TYPE_LCD;
+       ctx->manager.ops = &fimd_manager_ops;
+
+       ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC,
+                                      ctx->manager.type);
+       if (ret)
+               return ret;
 
        ctx->dev = dev;
        ctx->suspended = true;
@@ -1182,27 +1212,27 @@ static int fimd_probe(struct platform_device *pdev)
        init_waitqueue_head(&ctx->wait_vsync_queue);
        atomic_set(&ctx->wait_vsync_event, 0);
 
-       platform_set_drvdata(pdev, &fimd_manager);
-
-       fimd_manager.ctx = ctx;
+       platform_set_drvdata(pdev, ctx);
 
        ctx->display = exynos_dpi_probe(dev);
-       if (IS_ERR(ctx->display))
-               return PTR_ERR(ctx->display);
+       if (IS_ERR(ctx->display)) {
+               ret = PTR_ERR(ctx->display);
+               goto err_del_component;
+       }
 
-       pm_runtime_enable(&pdev->dev);
+       pm_runtime_enable(dev);
 
-       ret = component_add(&pdev->dev, &fimd_component_ops);
+       ret = component_add(dev, &fimd_component_ops);
        if (ret)
                goto err_disable_pm_runtime;
 
        return ret;
 
 err_disable_pm_runtime:
-       pm_runtime_disable(&pdev->dev);
+       pm_runtime_disable(dev);
 
 err_del_component:
-       exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
+       exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CRTC);
        return ret;
 }
 
index 72376d41c5129c609be952f623be43b2e44d949c..35d25889b476ebe281439e0c3363e61dd7b2ab5f 100644 (file)
@@ -40,7 +40,6 @@ static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
 
 #else
 
-struct dma_iommu_mapping;
 static inline int drm_create_iommu_mapping(struct drm_device *drm_dev)
 {
        return 0;
index 00d74b18f7cbd841f88d252d57ca47eb5d768863..d5ad17dfc24ddc1eafbce0c212a607c5598cbc1c 100644 (file)
@@ -426,18 +426,21 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
        c_node->start_work = ipp_create_cmd_work();
        if (IS_ERR(c_node->start_work)) {
                DRM_ERROR("failed to create start work.\n");
+               ret = PTR_ERR(c_node->start_work);
                goto err_remove_id;
        }
 
        c_node->stop_work = ipp_create_cmd_work();
        if (IS_ERR(c_node->stop_work)) {
                DRM_ERROR("failed to create stop work.\n");
+               ret = PTR_ERR(c_node->stop_work);
                goto err_free_start;
        }
 
        c_node->event_work = ipp_create_event_work();
        if (IS_ERR(c_node->event_work)) {
                DRM_ERROR("failed to create event work.\n");
+               ret = PTR_ERR(c_node->event_work);
                goto err_free_stop;
        }
 
index 50faf913e5749152f5d2a4dc29c655f33ce27f98..45899fb63272723003837d1e6f338a7b2afa3d87 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/component.h>
 
 #include <drm/exynos_drm.h>
 
@@ -28,7 +29,6 @@
 /* vidi has totally three virtual windows. */
 #define WINDOWS_NR             3
 
-#define get_vidi_mgr(dev)      platform_get_drvdata(to_platform_device(dev))
 #define ctx_from_connector(c)  container_of(c, struct vidi_context, \
                                        connector)
 
@@ -47,11 +47,13 @@ struct vidi_win_data {
 };
 
 struct vidi_context {
+       struct exynos_drm_manager       manager;
+       struct exynos_drm_display       display;
+       struct platform_device          *pdev;
        struct drm_device               *drm_dev;
        struct drm_crtc                 *crtc;
        struct drm_encoder              *encoder;
        struct drm_connector            connector;
-       struct exynos_drm_subdrv        subdrv;
        struct vidi_win_data            win_data[WINDOWS_NR];
        struct edid                     *raw_edid;
        unsigned int                    clkdiv;
@@ -66,6 +68,16 @@ struct vidi_context {
        int                             pipe;
 };
 
+static inline struct vidi_context *manager_to_vidi(struct exynos_drm_manager *m)
+{
+       return container_of(m, struct vidi_context, manager);
+}
+
+static inline struct vidi_context *display_to_vidi(struct exynos_drm_display *d)
+{
+       return container_of(d, struct vidi_context, display);
+}
+
 static const char fake_edid_info[] = {
        0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
        0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
@@ -93,7 +105,7 @@ static const char fake_edid_info[] = {
 
 static void vidi_apply(struct exynos_drm_manager *mgr)
 {
-       struct vidi_context *ctx = mgr->ctx;
+       struct vidi_context *ctx = manager_to_vidi(mgr);
        struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
        struct vidi_win_data *win_data;
        int i;
@@ -110,7 +122,7 @@ static void vidi_apply(struct exynos_drm_manager *mgr)
 
 static void vidi_commit(struct exynos_drm_manager *mgr)
 {
-       struct vidi_context *ctx = mgr->ctx;
+       struct vidi_context *ctx = manager_to_vidi(mgr);
 
        if (ctx->suspended)
                return;
@@ -118,7 +130,7 @@ static void vidi_commit(struct exynos_drm_manager *mgr)
 
 static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
 {
-       struct vidi_context *ctx = mgr->ctx;
+       struct vidi_context *ctx = manager_to_vidi(mgr);
 
        if (ctx->suspended)
                return -EPERM;
@@ -140,7 +152,7 @@ static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
 
 static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
 {
-       struct vidi_context *ctx = mgr->ctx;
+       struct vidi_context *ctx = manager_to_vidi(mgr);
 
        if (ctx->suspended)
                return;
@@ -152,7 +164,7 @@ static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
 static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
                        struct exynos_drm_overlay *overlay)
 {
-       struct vidi_context *ctx = mgr->ctx;
+       struct vidi_context *ctx = manager_to_vidi(mgr);
        struct vidi_win_data *win_data;
        int win;
        unsigned long offset;
@@ -204,7 +216,7 @@ static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
 
 static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
 {
-       struct vidi_context *ctx = mgr->ctx;
+       struct vidi_context *ctx = manager_to_vidi(mgr);
        struct vidi_win_data *win_data;
        int win = zpos;
 
@@ -229,7 +241,7 @@ static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
 
 static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
 {
-       struct vidi_context *ctx = mgr->ctx;
+       struct vidi_context *ctx = manager_to_vidi(mgr);
        struct vidi_win_data *win_data;
        int win = zpos;
 
@@ -247,7 +259,7 @@ static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
 
 static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
 {
-       struct vidi_context *ctx = mgr->ctx;
+       struct vidi_context *ctx = manager_to_vidi(mgr);
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -271,7 +283,7 @@ static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
 
 static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
 {
-       struct vidi_context *ctx = mgr->ctx;
+       struct vidi_context *ctx = manager_to_vidi(mgr);
 
        DRM_DEBUG_KMS("%d\n", mode);
 
@@ -297,7 +309,7 @@ static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
 static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
                        struct drm_device *drm_dev)
 {
-       struct vidi_context *ctx = mgr->ctx;
+       struct vidi_context *ctx = manager_to_vidi(mgr);
        struct exynos_drm_private *priv = drm_dev->dev_private;
 
        mgr->drm_dev = ctx->drm_dev = drm_dev;
@@ -316,11 +328,6 @@ static struct exynos_drm_manager_ops vidi_manager_ops = {
        .win_disable = vidi_win_disable,
 };
 
-static struct exynos_drm_manager vidi_manager = {
-       .type = EXYNOS_DISPLAY_TYPE_VIDI,
-       .ops = &vidi_manager_ops,
-};
-
 static void vidi_fake_vblank_handler(struct work_struct *work)
 {
        struct vidi_context *ctx = container_of(work, struct vidi_context,
@@ -349,9 +356,8 @@ static void vidi_fake_vblank_handler(struct work_struct *work)
 static int vidi_show_connection(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
+       struct vidi_context *ctx = dev_get_drvdata(dev);
        int rc;
-       struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
-       struct vidi_context *ctx = mgr->ctx;
 
        mutex_lock(&ctx->lock);
 
@@ -366,8 +372,7 @@ static int vidi_store_connection(struct device *dev,
                                struct device_attribute *attr,
                                const char *buf, size_t len)
 {
-       struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
-       struct vidi_context *ctx = mgr->ctx;
+       struct vidi_context *ctx = dev_get_drvdata(dev);
        int ret;
 
        ret = kstrtoint(buf, 0, &ctx->connected);
@@ -420,7 +425,7 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
                display = exynos_drm_get_display(encoder);
 
                if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) {
-                       ctx = display->ctx;
+                       ctx = display_to_vidi(display);
                        break;
                }
        }
@@ -530,7 +535,7 @@ static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
 static int vidi_create_connector(struct exynos_drm_display *display,
                                struct drm_encoder *encoder)
 {
-       struct vidi_context *ctx = display->ctx;
+       struct vidi_context *ctx = display_to_vidi(display);
        struct drm_connector *connector = &ctx->connector;
        int ret;
 
@@ -556,27 +561,22 @@ static struct exynos_drm_display_ops vidi_display_ops = {
        .create_connector = vidi_create_connector,
 };
 
-static struct exynos_drm_display vidi_display = {
-       .type = EXYNOS_DISPLAY_TYPE_VIDI,
-       .ops = &vidi_display_ops,
-};
-
-static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
+static int vidi_bind(struct device *dev, struct device *master, void *data)
 {
-       struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
-       struct vidi_context *ctx = mgr->ctx;
+       struct vidi_context *ctx = dev_get_drvdata(dev);
+       struct drm_device *drm_dev = data;
        struct drm_crtc *crtc = ctx->crtc;
        int ret;
 
-       vidi_mgr_initialize(mgr, drm_dev);
+       vidi_mgr_initialize(&ctx->manager, drm_dev);
 
-       ret = exynos_drm_crtc_create(&vidi_manager);
+       ret = exynos_drm_crtc_create(&ctx->manager);
        if (ret) {
                DRM_ERROR("failed to create crtc.\n");
                return ret;
        }
 
-       ret = exynos_drm_create_enc_conn(drm_dev, &vidi_display);
+       ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display);
        if (ret) {
                crtc->funcs->destroy(crtc);
                DRM_ERROR("failed to create encoder and connector.\n");
@@ -586,9 +586,18 @@ static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
        return 0;
 }
 
+
+static void vidi_unbind(struct device *dev, struct device *master, void *data)
+{
+}
+
+static const struct component_ops vidi_component_ops = {
+       .bind   = vidi_bind,
+       .unbind = vidi_unbind,
+};
+
 static int vidi_probe(struct platform_device *pdev)
 {
-       struct exynos_drm_subdrv *subdrv;
        struct vidi_context *ctx;
        int ret;
 
@@ -596,40 +605,54 @@ static int vidi_probe(struct platform_device *pdev)
        if (!ctx)
                return -ENOMEM;
 
+       ctx->manager.type = EXYNOS_DISPLAY_TYPE_VIDI;
+       ctx->manager.ops = &vidi_manager_ops;
+       ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI;
+       ctx->display.ops = &vidi_display_ops;
        ctx->default_win = 0;
+       ctx->pdev = pdev;
 
-       INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
-
-       vidi_manager.ctx = ctx;
-       vidi_display.ctx = ctx;
+       ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
+                                       ctx->manager.type);
+       if (ret)
+               return ret;
 
-       mutex_init(&ctx->lock);
+       ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
+                                       ctx->display.type);
+       if (ret)
+               goto err_del_crtc_component;
 
-       platform_set_drvdata(pdev, &vidi_manager);
+       INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
 
-       subdrv = &ctx->subdrv;
-       subdrv->dev = &pdev->dev;
-       subdrv->probe = vidi_subdrv_probe;
+       mutex_init(&ctx->lock);
 
-       ret = exynos_drm_subdrv_register(subdrv);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to register drm vidi device\n");
-               return ret;
-       }
+       platform_set_drvdata(pdev, ctx);
 
        ret = device_create_file(&pdev->dev, &dev_attr_connection);
        if (ret < 0) {
-               exynos_drm_subdrv_unregister(subdrv);
-               DRM_INFO("failed to create connection sysfs.\n");
+               DRM_ERROR("failed to create connection sysfs.\n");
+               goto err_del_conn_component;
        }
 
-       return 0;
+       ret = component_add(&pdev->dev, &vidi_component_ops);
+       if (ret)
+               goto err_remove_file;
+
+       return ret;
+
+err_remove_file:
+       device_remove_file(&pdev->dev, &dev_attr_connection);
+err_del_conn_component:
+       exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
+err_del_crtc_component:
+       exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
+
+       return ret;
 }
 
 static int vidi_remove(struct platform_device *pdev)
 {
-       struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
-       struct vidi_context *ctx = mgr->ctx;
+       struct vidi_context *ctx = platform_get_drvdata(pdev);
 
        if (ctx->raw_edid != (struct edid *)fake_edid_info) {
                kfree(ctx->raw_edid);
@@ -638,6 +661,10 @@ static int vidi_remove(struct platform_device *pdev)
                return -EINVAL;
        }
 
+       component_del(&pdev->dev, &vidi_component_ops);
+       exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
+       exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
+
        return 0;
 }
 
@@ -668,12 +695,19 @@ int exynos_drm_probe_vidi(void)
        return ret;
 }
 
+static int exynos_drm_remove_vidi_device(struct device *dev, void *data)
+{
+       platform_device_unregister(to_platform_device(dev));
+
+       return 0;
+}
+
 void exynos_drm_remove_vidi(void)
 {
-       struct vidi_context *ctx = vidi_manager.ctx;
-       struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
-       struct platform_device *pdev = to_platform_device(subdrv->dev);
+       int ret = driver_for_each_device(&vidi_driver.driver, NULL, NULL,
+                                        exynos_drm_remove_vidi_device);
+       /* silence compiler warning */
+       (void)ret;
 
        platform_driver_unregister(&vidi_driver);
-       platform_device_unregister(pdev);
 }
index 563a19e62eb2cb5ccd9e13a7f35bc589c9824431..5765a161abdd4b35c958086ad9fdf996b146dbc1 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/gpio.h>
 #include <media/s5p_hdmi.h>
 
-#define get_hdmi_display(dev)  platform_get_drvdata(to_platform_device(dev))
 #define ctx_from_connector(c)  container_of(c, struct hdmi_context, connector)
 
 #define HOTPLUG_DEBOUNCE_MS            1100
@@ -182,6 +181,7 @@ struct hdmi_conf_regs {
 };
 
 struct hdmi_context {
+       struct exynos_drm_display       display;
        struct device                   *dev;
        struct drm_device               *drm_dev;
        struct drm_connector            connector;
@@ -213,6 +213,11 @@ struct hdmi_context {
        enum hdmi_type                  type;
 };
 
+static inline struct hdmi_context *display_to_hdmi(struct exynos_drm_display *d)
+{
+       return container_of(d, struct hdmi_context, display);
+}
+
 struct hdmiphy_config {
        int pixel_clock;
        u8 conf[32];
@@ -1123,7 +1128,7 @@ static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
 static int hdmi_create_connector(struct exynos_drm_display *display,
                        struct drm_encoder *encoder)
 {
-       struct hdmi_context *hdata = display->ctx;
+       struct hdmi_context *hdata = display_to_hdmi(display);
        struct drm_connector *connector = &hdata->connector;
        int ret;
 
@@ -2000,7 +2005,7 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata,
 static void hdmi_mode_set(struct exynos_drm_display *display,
                        struct drm_display_mode *mode)
 {
-       struct hdmi_context *hdata = display->ctx;
+       struct hdmi_context *hdata = display_to_hdmi(display);
        struct drm_display_mode *m = mode;
 
        DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
@@ -2019,7 +2024,7 @@ static void hdmi_mode_set(struct exynos_drm_display *display,
 
 static void hdmi_commit(struct exynos_drm_display *display)
 {
-       struct hdmi_context *hdata = display->ctx;
+       struct hdmi_context *hdata = display_to_hdmi(display);
 
        mutex_lock(&hdata->hdmi_mutex);
        if (!hdata->powered) {
@@ -2033,7 +2038,7 @@ static void hdmi_commit(struct exynos_drm_display *display)
 
 static void hdmi_poweron(struct exynos_drm_display *display)
 {
-       struct hdmi_context *hdata = display->ctx;
+       struct hdmi_context *hdata = display_to_hdmi(display);
        struct hdmi_resources *res = &hdata->res;
 
        mutex_lock(&hdata->hdmi_mutex);
@@ -2064,7 +2069,7 @@ static void hdmi_poweron(struct exynos_drm_display *display)
 
 static void hdmi_poweroff(struct exynos_drm_display *display)
 {
-       struct hdmi_context *hdata = display->ctx;
+       struct hdmi_context *hdata = display_to_hdmi(display);
        struct hdmi_resources *res = &hdata->res;
 
        mutex_lock(&hdata->hdmi_mutex);
@@ -2099,7 +2104,7 @@ out:
 
 static void hdmi_dpms(struct exynos_drm_display *display, int mode)
 {
-       struct hdmi_context *hdata = display->ctx;
+       struct hdmi_context *hdata = display_to_hdmi(display);
        struct drm_encoder *encoder = hdata->encoder;
        struct drm_crtc *crtc = encoder->crtc;
        struct drm_crtc_helper_funcs *funcs = NULL;
@@ -2143,11 +2148,6 @@ static struct exynos_drm_display_ops hdmi_display_ops = {
        .commit         = hdmi_commit,
 };
 
-static struct exynos_drm_display hdmi_display = {
-       .type = EXYNOS_DISPLAY_TYPE_HDMI,
-       .ops = &hdmi_display_ops,
-};
-
 static void hdmi_hotplug_work_func(struct work_struct *work)
 {
        struct hdmi_context *hdata;
@@ -2302,12 +2302,11 @@ MODULE_DEVICE_TABLE (of, hdmi_match_types);
 static int hdmi_bind(struct device *dev, struct device *master, void *data)
 {
        struct drm_device *drm_dev = data;
-       struct hdmi_context *hdata;
+       struct hdmi_context *hdata = dev_get_drvdata(dev);
 
-       hdata = hdmi_display.ctx;
        hdata->drm_dev = drm_dev;
 
-       return exynos_drm_create_enc_conn(drm_dev, &hdmi_display);
+       return exynos_drm_create_enc_conn(drm_dev, &hdata->display);
 }
 
 static void hdmi_unbind(struct device *dev, struct device *master, void *data)
@@ -2349,31 +2348,28 @@ static int hdmi_probe(struct platform_device *pdev)
        struct resource *res;
        int ret;
 
-       ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
-                                       hdmi_display.type);
-       if (ret)
-               return ret;
-
-       if (!dev->of_node) {
-               ret = -ENODEV;
-               goto err_del_component;
-       }
+       if (!dev->of_node)
+               return -ENODEV;
 
        pdata = drm_hdmi_dt_parse_pdata(dev);
-       if (!pdata) {
-               ret = -EINVAL;
-               goto err_del_component;
-       }
+       if (!pdata)
+               return -EINVAL;
 
        hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
-       if (!hdata) {
-               ret = -ENOMEM;
-               goto err_del_component;
-       }
+       if (!hdata)
+               return -ENOMEM;
+
+       hdata->display.type = EXYNOS_DISPLAY_TYPE_HDMI;
+       hdata->display.ops = &hdmi_display_ops;
+
+       ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
+                                       hdata->display.type);
+       if (ret)
+               return ret;
 
        mutex_init(&hdata->hdmi_mutex);
 
-       platform_set_drvdata(pdev, &hdmi_display);
+       platform_set_drvdata(pdev, hdata);
 
        match = of_match_node(hdmi_match_types, dev->of_node);
        if (!match) {
@@ -2485,7 +2481,6 @@ out_get_phy_port:
        }
 
        pm_runtime_enable(dev);
-       hdmi_display.ctx = hdata;
 
        ret = component_add(&pdev->dev, &hdmi_component_ops);
        if (ret)
@@ -2510,7 +2505,7 @@ err_del_component:
 
 static int hdmi_remove(struct platform_device *pdev)
 {
-       struct hdmi_context *hdata = hdmi_display.ctx;
+       struct hdmi_context *hdata = platform_get_drvdata(pdev);
 
        cancel_delayed_work_sync(&hdata->hotplug_work);
 
index a41c84ee3a2d554a464219cf4000083b2e3fa4dd..820b76234ef4c5c6da02ebe50327066c5fe38d1a 100644 (file)
@@ -40,8 +40,6 @@
 #include "exynos_drm_iommu.h"
 #include "exynos_mixer.h"
 
-#define get_mixer_manager(dev) platform_get_drvdata(to_platform_device(dev))
-
 #define MIXER_WIN_NR           3
 #define MIXER_DEFAULT_WIN      0
 
@@ -86,6 +84,7 @@ enum mixer_version_id {
 };
 
 struct mixer_context {
+       struct exynos_drm_manager manager;
        struct platform_device *pdev;
        struct device           *dev;
        struct drm_device       *drm_dev;
@@ -104,6 +103,11 @@ struct mixer_context {
        atomic_t                wait_vsync_event;
 };
 
+static inline struct mixer_context *mgr_to_mixer(struct exynos_drm_manager *mgr)
+{
+       return container_of(mgr, struct mixer_context, manager);
+}
+
 struct mixer_drv_data {
        enum mixer_version_id   version;
        bool                                    is_vp_enabled;
@@ -854,7 +858,7 @@ static int mixer_initialize(struct exynos_drm_manager *mgr,
                        struct drm_device *drm_dev)
 {
        int ret;
-       struct mixer_context *mixer_ctx = mgr->ctx;
+       struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
        struct exynos_drm_private *priv;
        priv = drm_dev->dev_private;
 
@@ -885,7 +889,7 @@ static int mixer_initialize(struct exynos_drm_manager *mgr,
 
 static void mixer_mgr_remove(struct exynos_drm_manager *mgr)
 {
-       struct mixer_context *mixer_ctx = mgr->ctx;
+       struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
 
        if (is_drm_iommu_supported(mixer_ctx->drm_dev))
                drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
@@ -893,7 +897,7 @@ static void mixer_mgr_remove(struct exynos_drm_manager *mgr)
 
 static int mixer_enable_vblank(struct exynos_drm_manager *mgr)
 {
-       struct mixer_context *mixer_ctx = mgr->ctx;
+       struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
        struct mixer_resources *res = &mixer_ctx->mixer_res;
 
        if (!mixer_ctx->powered) {
@@ -910,7 +914,7 @@ static int mixer_enable_vblank(struct exynos_drm_manager *mgr)
 
 static void mixer_disable_vblank(struct exynos_drm_manager *mgr)
 {
-       struct mixer_context *mixer_ctx = mgr->ctx;
+       struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
        struct mixer_resources *res = &mixer_ctx->mixer_res;
 
        /* disable vsync interrupt */
@@ -920,7 +924,7 @@ static void mixer_disable_vblank(struct exynos_drm_manager *mgr)
 static void mixer_win_mode_set(struct exynos_drm_manager *mgr,
                        struct exynos_drm_overlay *overlay)
 {
-       struct mixer_context *mixer_ctx = mgr->ctx;
+       struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
        struct hdmi_win_data *win_data;
        int win;
 
@@ -971,7 +975,7 @@ static void mixer_win_mode_set(struct exynos_drm_manager *mgr,
 
 static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos)
 {
-       struct mixer_context *mixer_ctx = mgr->ctx;
+       struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
        int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
 
        DRM_DEBUG_KMS("win: %d\n", win);
@@ -993,7 +997,7 @@ static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos)
 
 static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
 {
-       struct mixer_context *mixer_ctx = mgr->ctx;
+       struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
        struct mixer_resources *res = &mixer_ctx->mixer_res;
        int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
        unsigned long flags;
@@ -1021,7 +1025,7 @@ static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
 
 static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
 {
-       struct mixer_context *mixer_ctx = mgr->ctx;
+       struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
 
        mutex_lock(&mixer_ctx->mixer_mutex);
        if (!mixer_ctx->powered) {
@@ -1048,7 +1052,7 @@ static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
 
 static void mixer_window_suspend(struct exynos_drm_manager *mgr)
 {
-       struct mixer_context *ctx = mgr->ctx;
+       struct mixer_context *ctx = mgr_to_mixer(mgr);
        struct hdmi_win_data *win_data;
        int i;
 
@@ -1062,7 +1066,7 @@ static void mixer_window_suspend(struct exynos_drm_manager *mgr)
 
 static void mixer_window_resume(struct exynos_drm_manager *mgr)
 {
-       struct mixer_context *ctx = mgr->ctx;
+       struct mixer_context *ctx = mgr_to_mixer(mgr);
        struct hdmi_win_data *win_data;
        int i;
 
@@ -1077,7 +1081,7 @@ static void mixer_window_resume(struct exynos_drm_manager *mgr)
 
 static void mixer_poweron(struct exynos_drm_manager *mgr)
 {
-       struct mixer_context *ctx = mgr->ctx;
+       struct mixer_context *ctx = mgr_to_mixer(mgr);
        struct mixer_resources *res = &ctx->mixer_res;
 
        mutex_lock(&ctx->mixer_mutex);
@@ -1111,7 +1115,7 @@ static void mixer_poweron(struct exynos_drm_manager *mgr)
 
 static void mixer_poweroff(struct exynos_drm_manager *mgr)
 {
-       struct mixer_context *ctx = mgr->ctx;
+       struct mixer_context *ctx = mgr_to_mixer(mgr);
        struct mixer_resources *res = &ctx->mixer_res;
 
        mutex_lock(&ctx->mixer_mutex);
@@ -1187,11 +1191,6 @@ static struct exynos_drm_manager_ops mixer_manager_ops = {
        .win_disable            = mixer_win_disable,
 };
 
-static struct exynos_drm_manager mixer_manager = {
-       .type                   = EXYNOS_DISPLAY_TYPE_HDMI,
-       .ops                    = &mixer_manager_ops,
-};
-
 static struct mixer_drv_data exynos5420_mxr_drv_data = {
        .version = MXR_VER_128_0_0_184,
        .is_vp_enabled = 0,
@@ -1249,48 +1248,17 @@ MODULE_DEVICE_TABLE(of, mixer_match_types);
 
 static int mixer_bind(struct device *dev, struct device *manager, void *data)
 {
-       struct platform_device *pdev = to_platform_device(dev);
+       struct mixer_context *ctx = dev_get_drvdata(dev);
        struct drm_device *drm_dev = data;
-       struct mixer_context *ctx;
-       struct mixer_drv_data *drv;
        int ret;
 
-       dev_info(dev, "probe start\n");
-
-       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
-       if (!ctx) {
-               DRM_ERROR("failed to alloc mixer context.\n");
-               return -ENOMEM;
-       }
-
-       mutex_init(&ctx->mixer_mutex);
-
-       if (dev->of_node) {
-               const struct of_device_id *match;
-               match = of_match_node(mixer_match_types, dev->of_node);
-               drv = (struct mixer_drv_data *)match->data;
-       } else {
-               drv = (struct mixer_drv_data *)
-                       platform_get_device_id(pdev)->driver_data;
-       }
-
-       ctx->pdev = pdev;
-       ctx->dev = dev;
-       ctx->vp_enabled = drv->is_vp_enabled;
-       ctx->has_sclk = drv->has_sclk;
-       ctx->mxr_ver = drv->version;
-       init_waitqueue_head(&ctx->wait_vsync_queue);
-       atomic_set(&ctx->wait_vsync_event, 0);
-
-       mixer_manager.ctx = ctx;
-       ret = mixer_initialize(&mixer_manager, drm_dev);
+       ret = mixer_initialize(&ctx->manager, drm_dev);
        if (ret)
                return ret;
 
-       platform_set_drvdata(pdev, &mixer_manager);
-       ret = exynos_drm_crtc_create(&mixer_manager);
+       ret = exynos_drm_crtc_create(&ctx->manager);
        if (ret) {
-               mixer_mgr_remove(&mixer_manager);
+               mixer_mgr_remove(&ctx->manager);
                return ret;
        }
 
@@ -1301,11 +1269,9 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
 
 static void mixer_unbind(struct device *dev, struct device *master, void *data)
 {
-       struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
+       struct mixer_context *ctx = dev_get_drvdata(dev);
 
-       dev_info(dev, "remove successful\n");
-
-       mixer_mgr_remove(mgr);
+       mixer_mgr_remove(&ctx->manager);
 
        pm_runtime_disable(dev);
 }
@@ -1317,22 +1283,62 @@ static const struct component_ops mixer_component_ops = {
 
 static int mixer_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
+       struct mixer_drv_data *drv;
+       struct mixer_context *ctx;
        int ret;
 
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx) {
+               DRM_ERROR("failed to alloc mixer context.\n");
+               return -ENOMEM;
+       }
+
+       mutex_init(&ctx->mixer_mutex);
+
+       ctx->manager.type = EXYNOS_DISPLAY_TYPE_HDMI;
+       ctx->manager.ops = &mixer_manager_ops;
+
+       if (dev->of_node) {
+               const struct of_device_id *match;
+
+               match = of_match_node(mixer_match_types, dev->of_node);
+               drv = (struct mixer_drv_data *)match->data;
+       } else {
+               drv = (struct mixer_drv_data *)
+                       platform_get_device_id(pdev)->driver_data;
+       }
+
+       ctx->pdev = pdev;
+       ctx->dev = dev;
+       ctx->vp_enabled = drv->is_vp_enabled;
+       ctx->has_sclk = drv->has_sclk;
+       ctx->mxr_ver = drv->version;
+       init_waitqueue_head(&ctx->wait_vsync_queue);
+       atomic_set(&ctx->wait_vsync_event, 0);
+
+       platform_set_drvdata(pdev, ctx);
+
        ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
-                                       mixer_manager.type);
+                                       ctx->manager.type);
        if (ret)
                return ret;
 
        ret = component_add(&pdev->dev, &mixer_component_ops);
-       if (ret)
+       if (ret) {
                exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
+               return ret;
+       }
+
+       pm_runtime_enable(dev);
 
        return ret;
 }
 
 static int mixer_remove(struct platform_device *pdev)
 {
+       pm_runtime_disable(&pdev->dev);
+
        component_del(&pdev->dev, &mixer_component_ops);
        exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
 
index b1531557637662af7c0e3bc576602514f3701d63..190e55f2f891046420942b6bb5d8423e25753254 100644 (file)
@@ -39,6 +39,7 @@ gma500_gfx-$(CONFIG_DRM_GMA3600) +=  cdv_device.o \
 gma500_gfx-$(CONFIG_DRM_GMA600) += oaktrail_device.o \
          oaktrail_crtc.o \
          oaktrail_lvds.o \
+         oaktrail_lvds_i2c.o \
          oaktrail_hdmi.o \
          oaktrail_hdmi_i2c.o
 
index 87885d8c06e849290be8dfb543dc0caaa88cac4d..6b43ae3ffd73e067f7b52a51cdde68fbab3f259a 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include <linux/freezer.h>
+#include <video/mipi_display.h>
 
 #include "mdfld_dsi_output.h"
 #include "mdfld_dsi_pkg_sender.h"
 
 #define MDFLD_DSI_READ_MAX_COUNT               5000
 
-enum data_type {
-       DSI_DT_GENERIC_SHORT_WRITE_0    = 0x03,
-       DSI_DT_GENERIC_SHORT_WRITE_1    = 0x13,
-       DSI_DT_GENERIC_SHORT_WRITE_2    = 0x23,
-       DSI_DT_GENERIC_READ_0           = 0x04,
-       DSI_DT_GENERIC_READ_1           = 0x14,
-       DSI_DT_GENERIC_READ_2           = 0x24,
-       DSI_DT_GENERIC_LONG_WRITE       = 0x29,
-       DSI_DT_DCS_SHORT_WRITE_0        = 0x05,
-       DSI_DT_DCS_SHORT_WRITE_1        = 0x15,
-       DSI_DT_DCS_READ                 = 0x06,
-       DSI_DT_DCS_LONG_WRITE           = 0x39,
-};
-
 enum {
        MDFLD_DSI_PANEL_MODE_SLEEP = 0x1,
 };
@@ -321,9 +308,9 @@ static int send_pkg_prepare(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
        u8 cmd;
 
        switch (data_type) {
-       case DSI_DT_DCS_SHORT_WRITE_0:
-       case DSI_DT_DCS_SHORT_WRITE_1:
-       case DSI_DT_DCS_LONG_WRITE:
+       case MIPI_DSI_DCS_SHORT_WRITE:
+       case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+       case MIPI_DSI_DCS_LONG_WRITE:
                cmd = *data;
                break;
        default:
@@ -334,12 +321,12 @@ static int send_pkg_prepare(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
        sender->status = MDFLD_DSI_PKG_SENDER_BUSY;
 
        /*wait for 120 milliseconds in case exit_sleep_mode just be sent*/
-       if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) {
+       if (unlikely(cmd == MIPI_DCS_ENTER_SLEEP_MODE)) {
                /*TODO: replace it with msleep later*/
                mdelay(120);
        }
 
-       if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) {
+       if (unlikely(cmd == MIPI_DCS_EXIT_SLEEP_MODE)) {
                /*TODO: replace it with msleep later*/
                mdelay(120);
        }
@@ -352,9 +339,9 @@ static int send_pkg_done(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
        u8 cmd;
 
        switch (data_type) {
-       case DSI_DT_DCS_SHORT_WRITE_0:
-       case DSI_DT_DCS_SHORT_WRITE_1:
-       case DSI_DT_DCS_LONG_WRITE:
+       case MIPI_DSI_DCS_SHORT_WRITE:
+       case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+       case MIPI_DSI_DCS_LONG_WRITE:
                cmd = *data;
                break;
        default:
@@ -362,15 +349,15 @@ static int send_pkg_done(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
        }
 
        /*update panel status*/
-       if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) {
+       if (unlikely(cmd == MIPI_DCS_ENTER_SLEEP_MODE)) {
                sender->panel_mode |= MDFLD_DSI_PANEL_MODE_SLEEP;
                /*TODO: replace it with msleep later*/
                mdelay(120);
-       } else if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) {
+       } else if (unlikely(cmd == MIPI_DCS_EXIT_SLEEP_MODE)) {
                sender->panel_mode &= ~MDFLD_DSI_PANEL_MODE_SLEEP;
                /*TODO: replace it with msleep later*/
                mdelay(120);
-       } else if (unlikely(cmd == DCS_SOFT_RESET)) {
+       } else if (unlikely(cmd == MIPI_DCS_SOFT_RESET)) {
                /*TODO: replace it with msleep later*/
                mdelay(5);
        }
@@ -405,19 +392,19 @@ static int send_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
        }
 
        switch (data_type) {
-       case DSI_DT_GENERIC_SHORT_WRITE_0:
-       case DSI_DT_GENERIC_SHORT_WRITE_1:
-       case DSI_DT_GENERIC_SHORT_WRITE_2:
-       case DSI_DT_GENERIC_READ_0:
-       case DSI_DT_GENERIC_READ_1:
-       case DSI_DT_GENERIC_READ_2:
-       case DSI_DT_DCS_SHORT_WRITE_0:
-       case DSI_DT_DCS_SHORT_WRITE_1:
-       case DSI_DT_DCS_READ:
+       case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
+       case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
+       case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
+       case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
+       case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
+       case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
+       case MIPI_DSI_DCS_SHORT_WRITE:
+       case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+       case MIPI_DSI_DCS_READ:
                ret = send_short_pkg(sender, data_type, data[0], data[1], hs);
                break;
-       case DSI_DT_GENERIC_LONG_WRITE:
-       case DSI_DT_DCS_LONG_WRITE:
+       case MIPI_DSI_GENERIC_LONG_WRITE:
+       case MIPI_DSI_DCS_LONG_WRITE:
                ret = send_long_pkg(sender, data_type, data, len, hs);
                break;
        }
@@ -440,7 +427,7 @@ int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
        }
 
        spin_lock_irqsave(&sender->lock, flags);
-       send_pkg(sender, DSI_DT_DCS_LONG_WRITE, data, len, hs);
+       send_pkg(sender, MIPI_DSI_DCS_LONG_WRITE, data, len, hs);
        spin_unlock_irqrestore(&sender->lock, flags);
 
        return 0;
@@ -461,10 +448,10 @@ int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
        data[0] = cmd;
 
        if (param_num) {
-               data_type = DSI_DT_DCS_SHORT_WRITE_1;
+               data_type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
                data[1] = param;
        } else {
-               data_type = DSI_DT_DCS_SHORT_WRITE_0;
+               data_type = MIPI_DSI_DCS_SHORT_WRITE;
                data[1] = 0;
        }
 
@@ -489,17 +476,17 @@ int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0,
 
        switch (param_num) {
        case 0:
-               data_type = DSI_DT_GENERIC_SHORT_WRITE_0;
+               data_type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM;
                data[0] = 0;
                data[1] = 0;
                break;
        case 1:
-               data_type = DSI_DT_GENERIC_SHORT_WRITE_1;
+               data_type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM;
                data[0] = param0;
                data[1] = 0;
                break;
        case 2:
-               data_type = DSI_DT_GENERIC_SHORT_WRITE_2;
+               data_type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM;
                data[0] = param0;
                data[1] = param1;
                break;
@@ -523,7 +510,7 @@ int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
        }
 
        spin_lock_irqsave(&sender->lock, flags);
-       send_pkg(sender, DSI_DT_GENERIC_LONG_WRITE, data, len, hs);
+       send_pkg(sender, MIPI_DSI_GENERIC_LONG_WRITE, data, len, hs);
        spin_unlock_irqrestore(&sender->lock, flags);
 
        return 0;
@@ -594,7 +581,7 @@ int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
                return -EINVAL;
        }
 
-       return __read_panel_data(sender, DSI_DT_DCS_READ, &cmd, 1,
+       return __read_panel_data(sender, MIPI_DSI_DCS_READ, &cmd, 1,
                                data, len, hs);
 }
 
index 459cd7ea8b81a098e9cf9ac8596d6105c7a7df44..0478a21c15d52d1d0eae8604183c2bfd39b7323e 100644 (file)
@@ -62,18 +62,6 @@ struct mdfld_dsi_pkg_sender {
        u32 mipi_cmd_len_reg;
 };
 
-/* DCS definitions */
-#define DCS_SOFT_RESET                 0x01
-#define DCS_ENTER_SLEEP_MODE           0x10
-#define DCS_EXIT_SLEEP_MODE            0x11
-#define DCS_SET_DISPLAY_OFF            0x28
-#define DCS_SET_DISPLAY_ON             0x29
-#define DCS_SET_COLUMN_ADDRESS         0x2a
-#define DCS_SET_PAGE_ADDRESS           0x2b
-#define DCS_WRITE_MEM_START            0x2c
-#define DCS_SET_TEAR_OFF               0x34
-#define DCS_SET_TEAR_ON                        0x35
-
 extern int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector,
                                        int pipe);
 extern void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender);
index 0d39da6e8b7a0627d7923d70b795a3f31db69e04..83bbc271bcfb5e92e1321a5a5842ea1fab26830a 100644 (file)
@@ -359,22 +359,26 @@ void oaktrail_lvds_init(struct drm_device *dev,
         *    if closed, act like it's not there for now
         */
 
+       edid = NULL;
        mutex_lock(&dev->mode_config.mutex);
        i2c_adap = i2c_get_adapter(dev_priv->ops->i2c_bus);
-       if (i2c_adap == NULL)
-               dev_err(dev->dev, "No ddc adapter available!\n");
+       if (i2c_adap)
+               edid = drm_get_edid(connector, i2c_adap);
+       if (edid == NULL && dev_priv->lpc_gpio_base) {
+               oaktrail_lvds_i2c_init(encoder);
+               if (gma_encoder->ddc_bus != NULL) {
+                       i2c_adap = &gma_encoder->ddc_bus->adapter;
+                       edid = drm_get_edid(connector, i2c_adap);
+               }
+       }
        /*
         * Attempt to get the fixed panel mode from DDC.  Assume that the
         * preferred mode is the right one.
         */
-       if (i2c_adap) {
-               edid = drm_get_edid(connector, i2c_adap);
-               if (edid) {
-                       drm_mode_connector_update_edid_property(connector,
-                                                                       edid);
-                       drm_add_edid_modes(connector, edid);
-                       kfree(edid);
-               }
+       if (edid) {
+               drm_mode_connector_update_edid_property(connector, edid);
+               drm_add_edid_modes(connector, edid);
+               kfree(edid);
 
                list_for_each_entry(scan, &connector->probed_modes, head) {
                        if (scan->type & DRM_MODE_TYPE_PREFERRED) {
@@ -383,7 +387,8 @@ void oaktrail_lvds_init(struct drm_device *dev,
                                goto out;       /* FIXME: check for quirks */
                        }
                }
-       }
+       } else
+               dev_err(dev->dev, "No ddc adapter available!\n");
        /*
         * If we didn't get EDID, try geting panel timing
         * from configuration data
@@ -411,8 +416,10 @@ failed_find:
        mutex_unlock(&dev->mode_config.mutex);
 
        dev_dbg(dev->dev, "No LVDS modes found, disabling.\n");
-       if (gma_encoder->ddc_bus)
+       if (gma_encoder->ddc_bus) {
                psb_intel_i2c_destroy(gma_encoder->ddc_bus);
+               gma_encoder->ddc_bus = NULL;
+       }
 
 /* failed_ddc: */
 
diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c b/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c
new file mode 100644 (file)
index 0000000..f913a62
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2002-2010, Intel Corporation.
+ * Copyright (c) 2014 ATRON electronic GmbH
+ *   Author: Jan Safrata <jan.nikitenko@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include <drm/drmP.h>
+#include "psb_drv.h"
+#include "psb_intel_reg.h"
+
+
+/*
+ * LPC GPIO based I2C bus for LVDS of Atom E6xx
+ */
+
+/*-----------------------------------------------------------------------------
+ * LPC Register Offsets. Used for LVDS GPIO Bit Bashing. Registers are part
+ * Atom E6xx [D31:F0]
+ ----------------------------------------------------------------------------*/
+#define RGEN    0x20
+#define RGIO    0x24
+#define RGLVL   0x28
+#define RGTPE   0x2C
+#define RGTNE   0x30
+#define RGGPE   0x34
+#define RGSMI   0x38
+#define RGTS    0x3C
+
+/* The LVDS GPIO clock lines are GPIOSUS[3]
+ * The LVDS GPIO data lines are GPIOSUS[4]
+ */
+#define GPIO_CLOCK     0x08
+#define GPIO_DATA      0x10
+
+#define LPC_READ_REG(chan, r) inl((chan)->reg + (r))
+#define LPC_WRITE_REG(chan, r, val) outl((val), (chan)->reg + (r))
+
+static int get_clock(void *data)
+{
+       struct psb_intel_i2c_chan *chan = data;
+       u32 val, tmp;
+
+       val = LPC_READ_REG(chan, RGIO);
+       val |= GPIO_CLOCK;
+       LPC_WRITE_REG(chan, RGIO, val);
+       tmp = LPC_READ_REG(chan, RGLVL);
+       val = (LPC_READ_REG(chan, RGLVL) & GPIO_CLOCK) ? 1 : 0;
+
+       return val;
+}
+
+static int get_data(void *data)
+{
+       struct psb_intel_i2c_chan *chan = data;
+       u32 val, tmp;
+
+       val = LPC_READ_REG(chan, RGIO);
+       val |= GPIO_DATA;
+       LPC_WRITE_REG(chan, RGIO, val);
+       tmp = LPC_READ_REG(chan, RGLVL);
+       val = (LPC_READ_REG(chan, RGLVL) & GPIO_DATA) ? 1 : 0;
+
+       return val;
+}
+
+static void set_clock(void *data, int state_high)
+{
+       struct psb_intel_i2c_chan *chan = data;
+       u32 val;
+
+       if (state_high) {
+               val = LPC_READ_REG(chan, RGIO);
+               val |= GPIO_CLOCK;
+               LPC_WRITE_REG(chan, RGIO, val);
+       } else {
+               val = LPC_READ_REG(chan, RGIO);
+               val &= ~GPIO_CLOCK;
+               LPC_WRITE_REG(chan, RGIO, val);
+               val = LPC_READ_REG(chan, RGLVL);
+               val &= ~GPIO_CLOCK;
+               LPC_WRITE_REG(chan, RGLVL, val);
+       }
+}
+
+static void set_data(void *data, int state_high)
+{
+       struct psb_intel_i2c_chan *chan = data;
+       u32 val;
+
+       if (state_high) {
+               val = LPC_READ_REG(chan, RGIO);
+               val |= GPIO_DATA;
+               LPC_WRITE_REG(chan, RGIO, val);
+       } else {
+               val = LPC_READ_REG(chan, RGIO);
+               val &= ~GPIO_DATA;
+               LPC_WRITE_REG(chan, RGIO, val);
+               val = LPC_READ_REG(chan, RGLVL);
+               val &= ~GPIO_DATA;
+               LPC_WRITE_REG(chan, RGLVL, val);
+       }
+}
+
+void oaktrail_lvds_i2c_init(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct gma_encoder *gma_encoder = to_gma_encoder(encoder);
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       struct psb_intel_i2c_chan *chan;
+
+       chan = kzalloc(sizeof(struct psb_intel_i2c_chan), GFP_KERNEL);
+       if (!chan)
+               return;
+
+       chan->drm_dev = dev;
+       chan->reg = dev_priv->lpc_gpio_base;
+       strncpy(chan->adapter.name, "gma500 LPC",  I2C_NAME_SIZE - 1);
+       chan->adapter.owner = THIS_MODULE;
+       chan->adapter.algo_data = &chan->algo;
+       chan->adapter.dev.parent = &dev->pdev->dev;
+       chan->algo.setsda = set_data;
+       chan->algo.setscl = set_clock;
+       chan->algo.getsda = get_data;
+       chan->algo.getscl = get_clock;
+       chan->algo.udelay = 100;
+       chan->algo.timeout = usecs_to_jiffies(2200);
+       chan->algo.data = chan;
+
+       i2c_set_adapdata(&chan->adapter, chan);
+
+       set_data(chan, 1);
+       set_clock(chan, 1);
+       udelay(50);
+
+       if (i2c_bit_add_bus(&chan->adapter)) {
+               kfree(chan);
+               return;
+       }
+
+       gma_encoder->ddc_bus = chan;
+}
index 6ec3a905fdd274bbcd1ec169efc802e8cf1663be..92e7e5795398e80a6ab46f51d3aad4d22a4e8346 100644 (file)
@@ -212,6 +212,8 @@ static int psb_driver_unload(struct drm_device *dev)
                }
                if (dev_priv->aux_pdev)
                        pci_dev_put(dev_priv->aux_pdev);
+               if (dev_priv->lpc_pdev)
+                       pci_dev_put(dev_priv->lpc_pdev);
 
                /* Destroy VBT data */
                psb_intel_destroy_bios(dev);
@@ -280,6 +282,24 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags)
                        DRM_DEBUG_KMS("Couldn't find aux pci device");
                }
                dev_priv->gmbus_reg = dev_priv->aux_reg;
+
+               dev_priv->lpc_pdev = pci_get_bus_and_slot(0, PCI_DEVFN(31, 0));
+               if (dev_priv->lpc_pdev) {
+                       pci_read_config_word(dev_priv->lpc_pdev, PSB_LPC_GBA,
+                               &dev_priv->lpc_gpio_base);
+                       pci_write_config_dword(dev_priv->lpc_pdev, PSB_LPC_GBA,
+                               (u32)dev_priv->lpc_gpio_base | (1L<<31));
+                       pci_read_config_word(dev_priv->lpc_pdev, PSB_LPC_GBA,
+                               &dev_priv->lpc_gpio_base);
+                       dev_priv->lpc_gpio_base &= 0xffc0;
+                       if (dev_priv->lpc_gpio_base)
+                               DRM_DEBUG_KMS("Found LPC GPIO at 0x%04x\n",
+                                               dev_priv->lpc_gpio_base);
+                       else {
+                               pci_dev_put(dev_priv->lpc_pdev);
+                               dev_priv->lpc_pdev = NULL;
+                       }
+               }
        } else {
                dev_priv->gmbus_reg = dev_priv->vdc_reg;
        }
index 55ebe2bd88dd75972b10c5cae18ed44cb3a50fd7..e38057b918657de7812e18071e084ae7538db8c8 100644 (file)
@@ -83,6 +83,7 @@ enum {
 #define PSB_PGETBL_CTL          0x2020
 #define _PSB_PGETBL_ENABLED     0x00000001
 #define PSB_SGX_2D_SLAVE_PORT   0x4000
+#define PSB_LPC_GBA             0x44
 
 /* TODO: To get rid of */
 #define PSB_TT_PRIV0_LIMIT      (256*1024*1024)
@@ -441,6 +442,7 @@ struct psb_ops;
 struct drm_psb_private {
        struct drm_device *dev;
        struct pci_dev *aux_pdev; /* Currently only used by mrst */
+       struct pci_dev *lpc_pdev; /* Currently only used by mrst */
        const struct psb_ops *ops;
        const struct psb_offset *regmap;
        
@@ -470,6 +472,7 @@ struct drm_psb_private {
        uint8_t __iomem *sgx_reg;
        uint8_t __iomem *vdc_reg;
        uint8_t __iomem *aux_reg; /* Auxillary vdc pipe regs */
+       uint16_t lpc_gpio_base;
        uint32_t gatt_free_offset;
 
        /* Fencing / irq */
index 336bd3aa1a066868af57f131c3260629abdb27c0..860dd2177ca15269bfedc7cf1ca2b4dafc3bddae 100644 (file)
@@ -223,6 +223,7 @@ extern void oaktrail_lvds_init(struct drm_device *dev,
 extern void oaktrail_wait_for_INTR_PKT_SENT(struct drm_device *dev);
 extern void oaktrail_dsi_init(struct drm_device *dev,
                           struct psb_intel_mode_device *mode_dev);
+extern void oaktrail_lvds_i2c_init(struct drm_encoder *encoder);
 extern void mid_dsi_init(struct drm_device *dev,
                    struct psb_intel_mode_device *mode_dev, int dsi_num);
 
index 4d341db462a2442878991e45a3438d770f1afe64..22c7ed63a001df43190a26ffc070a69c183f729c 100644 (file)
@@ -1,6 +1,12 @@
 menu "I2C encoder or helper chips"
      depends on DRM && DRM_KMS_HELPER && I2C
 
+config DRM_I2C_ADV7511
+       tristate "AV7511 encoder"
+       select REGMAP_I2C
+       help
+         Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders.
+
 config DRM_I2C_CH7006
        tristate "Chrontel ch7006 TV encoder"
        default m if DRM_NOUVEAU
index 43aa33baebed8e7888c07c0f818848cc1adb80f3..2c72eb584ab7c628254ecfec90d5de70773fab4e 100644 (file)
@@ -1,5 +1,7 @@
 ccflags-y := -Iinclude/drm
 
+obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511.o
+
 ch7006-y := ch7006_drv.o ch7006_mode.o
 obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o
 
diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
new file mode 100644 (file)
index 0000000..faf1c0c
--- /dev/null
@@ -0,0 +1,1010 @@
+/*
+ * Analog Devices ADV7511 HDMI transmitter driver
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+
+#include "adv7511.h"
+
+struct adv7511 {
+       struct i2c_client *i2c_main;
+       struct i2c_client *i2c_edid;
+
+       struct regmap *regmap;
+       struct regmap *packet_memory_regmap;
+       enum drm_connector_status status;
+       int dpms_mode;
+
+       unsigned int f_tmds;
+
+       unsigned int current_edid_segment;
+       uint8_t edid_buf[256];
+
+       wait_queue_head_t wq;
+       struct drm_encoder *encoder;
+
+       bool embedded_sync;
+       enum adv7511_sync_polarity vsync_polarity;
+       enum adv7511_sync_polarity hsync_polarity;
+       bool rgb;
+
+       struct edid *edid;
+
+       struct gpio_desc *gpio_pd;
+};
+
+static struct adv7511 *encoder_to_adv7511(struct drm_encoder *encoder)
+{
+       return to_encoder_slave(encoder)->slave_priv;
+}
+
+/* ADI recommended values for proper operation. */
+static const struct reg_default adv7511_fixed_registers[] = {
+       { 0x98, 0x03 },
+       { 0x9a, 0xe0 },
+       { 0x9c, 0x30 },
+       { 0x9d, 0x61 },
+       { 0xa2, 0xa4 },
+       { 0xa3, 0xa4 },
+       { 0xe0, 0xd0 },
+       { 0xf9, 0x00 },
+       { 0x55, 0x02 },
+};
+
+/* -----------------------------------------------------------------------------
+ * Register access
+ */
+
+static const uint8_t adv7511_register_defaults[] = {
+       0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00 */
+       0x00, 0x00, 0x01, 0x0e, 0xbc, 0x18, 0x01, 0x13,
+       0x25, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */
+       0x46, 0x62, 0x04, 0xa8, 0x00, 0x00, 0x1c, 0x84,
+       0x1c, 0xbf, 0x04, 0xa8, 0x1e, 0x70, 0x02, 0x1e, /* 20 */
+       0x00, 0x00, 0x04, 0xa8, 0x08, 0x12, 0x1b, 0xac,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 30 */
+       0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0,
+       0x00, 0x50, 0x90, 0x7e, 0x79, 0x70, 0x00, 0x00, /* 40 */
+       0x00, 0xa8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x02, 0x0d, 0x00, 0x00, 0x00, 0x00, /* 50 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 70 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 80 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 90 */
+       0x0b, 0x02, 0x00, 0x18, 0x5a, 0x60, 0x00, 0x00,
+       0x00, 0x00, 0x80, 0x80, 0x08, 0x04, 0x00, 0x00, /* a0 */
+       0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x14,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b0 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c0 */
+       0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x01, 0x04,
+       0x30, 0xff, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, /* d0 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01,
+       0x80, 0x75, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, /* e0 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x11, 0x00, /* f0 */
+       0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static bool adv7511_register_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case ADV7511_REG_CHIP_REVISION:
+       case ADV7511_REG_SPDIF_FREQ:
+       case ADV7511_REG_CTS_AUTOMATIC1:
+       case ADV7511_REG_CTS_AUTOMATIC2:
+       case ADV7511_REG_VIC_DETECTED:
+       case ADV7511_REG_VIC_SEND:
+       case ADV7511_REG_AUX_VIC_DETECTED:
+       case ADV7511_REG_STATUS:
+       case ADV7511_REG_GC(1):
+       case ADV7511_REG_INT(0):
+       case ADV7511_REG_INT(1):
+       case ADV7511_REG_PLL_STATUS:
+       case ADV7511_REG_AN(0):
+       case ADV7511_REG_AN(1):
+       case ADV7511_REG_AN(2):
+       case ADV7511_REG_AN(3):
+       case ADV7511_REG_AN(4):
+       case ADV7511_REG_AN(5):
+       case ADV7511_REG_AN(6):
+       case ADV7511_REG_AN(7):
+       case ADV7511_REG_HDCP_STATUS:
+       case ADV7511_REG_BCAPS:
+       case ADV7511_REG_BKSV(0):
+       case ADV7511_REG_BKSV(1):
+       case ADV7511_REG_BKSV(2):
+       case ADV7511_REG_BKSV(3):
+       case ADV7511_REG_BKSV(4):
+       case ADV7511_REG_DDC_STATUS:
+       case ADV7511_REG_BSTATUS(0):
+       case ADV7511_REG_BSTATUS(1):
+       case ADV7511_REG_CHIP_ID_HIGH:
+       case ADV7511_REG_CHIP_ID_LOW:
+               return true;
+       }
+
+       return false;
+}
+
+static const struct regmap_config adv7511_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = 0xff,
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults_raw = adv7511_register_defaults,
+       .num_reg_defaults_raw = ARRAY_SIZE(adv7511_register_defaults),
+
+       .volatile_reg = adv7511_register_volatile,
+};
+
+/* -----------------------------------------------------------------------------
+ * Hardware configuration
+ */
+
+static void adv7511_set_colormap(struct adv7511 *adv7511, bool enable,
+                                const uint16_t *coeff,
+                                unsigned int scaling_factor)
+{
+       unsigned int i;
+
+       regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(1),
+                          ADV7511_CSC_UPDATE_MODE, ADV7511_CSC_UPDATE_MODE);
+
+       if (enable) {
+               for (i = 0; i < 12; ++i) {
+                       regmap_update_bits(adv7511->regmap,
+                                          ADV7511_REG_CSC_UPPER(i),
+                                          0x1f, coeff[i] >> 8);
+                       regmap_write(adv7511->regmap,
+                                    ADV7511_REG_CSC_LOWER(i),
+                                    coeff[i] & 0xff);
+               }
+       }
+
+       if (enable)
+               regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(0),
+                                  0xe0, 0x80 | (scaling_factor << 5));
+       else
+               regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(0),
+                                  0x80, 0x00);
+
+       regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(1),
+                          ADV7511_CSC_UPDATE_MODE, 0);
+}
+
+static int adv7511_packet_enable(struct adv7511 *adv7511, unsigned int packet)
+{
+       if (packet & 0xff)
+               regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE0,
+                                  packet, 0xff);
+
+       if (packet & 0xff00) {
+               packet >>= 8;
+               regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,
+                                  packet, 0xff);
+       }
+
+       return 0;
+}
+
+static int adv7511_packet_disable(struct adv7511 *adv7511, unsigned int packet)
+{
+       if (packet & 0xff)
+               regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE0,
+                                  packet, 0x00);
+
+       if (packet & 0xff00) {
+               packet >>= 8;
+               regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,
+                                  packet, 0x00);
+       }
+
+       return 0;
+}
+
+/* Coefficients for adv7511 color space conversion */
+static const uint16_t adv7511_csc_ycbcr_to_rgb[] = {
+       0x0734, 0x04ad, 0x0000, 0x1c1b,
+       0x1ddc, 0x04ad, 0x1f24, 0x0135,
+       0x0000, 0x04ad, 0x087c, 0x1b77,
+};
+
+static void adv7511_set_config_csc(struct adv7511 *adv7511,
+                                  struct drm_connector *connector,
+                                  bool rgb)
+{
+       struct adv7511_video_config config;
+       bool output_format_422, output_format_ycbcr;
+       unsigned int mode;
+       uint8_t infoframe[17];
+
+       if (adv7511->edid)
+               config.hdmi_mode = drm_detect_hdmi_monitor(adv7511->edid);
+       else
+               config.hdmi_mode = false;
+
+       hdmi_avi_infoframe_init(&config.avi_infoframe);
+
+       config.avi_infoframe.scan_mode = HDMI_SCAN_MODE_UNDERSCAN;
+
+       if (rgb) {
+               config.csc_enable = false;
+               config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB;
+       } else {
+               config.csc_scaling_factor = ADV7511_CSC_SCALING_4;
+               config.csc_coefficents = adv7511_csc_ycbcr_to_rgb;
+
+               if ((connector->display_info.color_formats &
+                    DRM_COLOR_FORMAT_YCRCB422) &&
+                   config.hdmi_mode) {
+                       config.csc_enable = false;
+                       config.avi_infoframe.colorspace =
+                               HDMI_COLORSPACE_YUV422;
+               } else {
+                       config.csc_enable = true;
+                       config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB;
+               }
+       }
+
+       if (config.hdmi_mode) {
+               mode = ADV7511_HDMI_CFG_MODE_HDMI;
+
+               switch (config.avi_infoframe.colorspace) {
+               case HDMI_COLORSPACE_YUV444:
+                       output_format_422 = false;
+                       output_format_ycbcr = true;
+                       break;
+               case HDMI_COLORSPACE_YUV422:
+                       output_format_422 = true;
+                       output_format_ycbcr = true;
+                       break;
+               default:
+                       output_format_422 = false;
+                       output_format_ycbcr = false;
+                       break;
+               }
+       } else {
+               mode = ADV7511_HDMI_CFG_MODE_DVI;
+               output_format_422 = false;
+               output_format_ycbcr = false;
+       }
+
+       adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME);
+
+       adv7511_set_colormap(adv7511, config.csc_enable,
+                            config.csc_coefficents,
+                            config.csc_scaling_factor);
+
+       regmap_update_bits(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG1, 0x81,
+                          (output_format_422 << 7) | output_format_ycbcr);
+
+       regmap_update_bits(adv7511->regmap, ADV7511_REG_HDCP_HDMI_CFG,
+                          ADV7511_HDMI_CFG_MODE_MASK, mode);
+
+       hdmi_avi_infoframe_pack(&config.avi_infoframe, infoframe,
+                               sizeof(infoframe));
+
+       /* The AVI infoframe id is not configurable */
+       regmap_bulk_write(adv7511->regmap, ADV7511_REG_AVI_INFOFRAME_VERSION,
+                         infoframe + 1, sizeof(infoframe) - 1);
+
+       adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME);
+}
+
+static void adv7511_set_link_config(struct adv7511 *adv7511,
+                                   const struct adv7511_link_config *config)
+{
+       /*
+        * The input style values documented in the datasheet don't match the
+        * hardware register field values :-(
+        */
+       static const unsigned int input_styles[4] = { 0, 2, 1, 3 };
+
+       unsigned int clock_delay;
+       unsigned int color_depth;
+       unsigned int input_id;
+
+       clock_delay = (config->clock_delay + 1200) / 400;
+       color_depth = config->input_color_depth == 8 ? 3
+                   : (config->input_color_depth == 10 ? 1 : 2);
+
+       /* TODO Support input ID 6 */
+       if (config->input_colorspace != HDMI_COLORSPACE_YUV422)
+               input_id = config->input_clock == ADV7511_INPUT_CLOCK_DDR
+                        ? 5 : 0;
+       else if (config->input_clock == ADV7511_INPUT_CLOCK_DDR)
+               input_id = config->embedded_sync ? 8 : 7;
+       else if (config->input_clock == ADV7511_INPUT_CLOCK_2X)
+               input_id = config->embedded_sync ? 4 : 3;
+       else
+               input_id = config->embedded_sync ? 2 : 1;
+
+       regmap_update_bits(adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG, 0xf,
+                          input_id);
+       regmap_update_bits(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG1, 0x7e,
+                          (color_depth << 4) |
+                          (input_styles[config->input_style] << 2));
+       regmap_write(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG2,
+                    config->input_justification << 3);
+       regmap_write(adv7511->regmap, ADV7511_REG_TIMING_GEN_SEQ,
+                    config->sync_pulse << 2);
+
+       regmap_write(adv7511->regmap, 0xba, clock_delay << 5);
+
+       adv7511->embedded_sync = config->embedded_sync;
+       adv7511->hsync_polarity = config->hsync_polarity;
+       adv7511->vsync_polarity = config->vsync_polarity;
+       adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt and hotplug detection
+ */
+
+static bool adv7511_hpd(struct adv7511 *adv7511)
+{
+       unsigned int irq0;
+       int ret;
+
+       ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0);
+       if (ret < 0)
+               return false;
+
+       if (irq0 & ADV7511_INT0_HDP) {
+               regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
+                            ADV7511_INT0_HDP);
+               return true;
+       }
+
+       return false;
+}
+
+static irqreturn_t adv7511_irq_handler(int irq, void *devid)
+{
+       struct adv7511 *adv7511 = devid;
+
+       if (adv7511_hpd(adv7511))
+               drm_helper_hpd_irq_event(adv7511->encoder->dev);
+
+       wake_up_all(&adv7511->wq);
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int adv7511_is_interrupt_pending(struct adv7511 *adv7511,
+                                                unsigned int irq)
+{
+       unsigned int irq0, irq1;
+       unsigned int pending;
+       int ret;
+
+       ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0);
+       if (ret < 0)
+               return 0;
+       ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(1), &irq1);
+       if (ret < 0)
+               return 0;
+
+       pending = (irq1 << 8) | irq0;
+
+       return pending & irq;
+}
+
+static int adv7511_wait_for_interrupt(struct adv7511 *adv7511, int irq,
+                                     int timeout)
+{
+       unsigned int pending;
+       int ret;
+
+       if (adv7511->i2c_main->irq) {
+               ret = wait_event_interruptible_timeout(adv7511->wq,
+                               adv7511_is_interrupt_pending(adv7511, irq),
+                               msecs_to_jiffies(timeout));
+               if (ret <= 0)
+                       return 0;
+               pending = adv7511_is_interrupt_pending(adv7511, irq);
+       } else {
+               if (timeout < 25)
+                       timeout = 25;
+               do {
+                       pending = adv7511_is_interrupt_pending(adv7511, irq);
+                       if (pending)
+                               break;
+                       msleep(25);
+                       timeout -= 25;
+               } while (timeout >= 25);
+       }
+
+       return pending;
+}
+
+/* -----------------------------------------------------------------------------
+ * EDID retrieval
+ */
+
+static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block,
+                                 size_t len)
+{
+       struct adv7511 *adv7511 = data;
+       struct i2c_msg xfer[2];
+       uint8_t offset;
+       unsigned int i;
+       int ret;
+
+       if (len > 128)
+               return -EINVAL;
+
+       if (adv7511->current_edid_segment != block / 2) {
+               unsigned int status;
+
+               ret = regmap_read(adv7511->regmap, ADV7511_REG_DDC_STATUS,
+                                 &status);
+               if (ret < 0)
+                       return ret;
+
+               if (status != 2) {
+                       regmap_write(adv7511->regmap, ADV7511_REG_EDID_SEGMENT,
+                                    block);
+                       ret = adv7511_wait_for_interrupt(adv7511,
+                                       ADV7511_INT0_EDID_READY |
+                                       ADV7511_INT1_DDC_ERROR, 200);
+
+                       if (!(ret & ADV7511_INT0_EDID_READY))
+                               return -EIO;
+               }
+
+               regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
+                            ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR);
+
+               /* Break this apart, hopefully more I2C controllers will
+                * support 64 byte transfers than 256 byte transfers
+                */
+
+               xfer[0].addr = adv7511->i2c_edid->addr;
+               xfer[0].flags = 0;
+               xfer[0].len = 1;
+               xfer[0].buf = &offset;
+               xfer[1].addr = adv7511->i2c_edid->addr;
+               xfer[1].flags = I2C_M_RD;
+               xfer[1].len = 64;
+               xfer[1].buf = adv7511->edid_buf;
+
+               offset = 0;
+
+               for (i = 0; i < 4; ++i) {
+                       ret = i2c_transfer(adv7511->i2c_edid->adapter, xfer,
+                                          ARRAY_SIZE(xfer));
+                       if (ret < 0)
+                               return ret;
+                       else if (ret != 2)
+                               return -EIO;
+
+                       xfer[1].buf += 64;
+                       offset += 64;
+               }
+
+               adv7511->current_edid_segment = block / 2;
+       }
+
+       if (block % 2 == 0)
+               memcpy(buf, adv7511->edid_buf, len);
+       else
+               memcpy(buf, adv7511->edid_buf + 128, len);
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Encoder operations
+ */
+
+static int adv7511_get_modes(struct drm_encoder *encoder,
+                            struct drm_connector *connector)
+{
+       struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+       struct edid *edid;
+       unsigned int count;
+
+       /* Reading the EDID only works if the device is powered */
+       if (adv7511->dpms_mode != DRM_MODE_DPMS_ON) {
+               regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
+                            ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR);
+               regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
+                                  ADV7511_POWER_POWER_DOWN, 0);
+               adv7511->current_edid_segment = -1;
+       }
+
+       edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511);
+
+       if (adv7511->dpms_mode != DRM_MODE_DPMS_ON)
+               regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
+                                  ADV7511_POWER_POWER_DOWN,
+                                  ADV7511_POWER_POWER_DOWN);
+
+       kfree(adv7511->edid);
+       adv7511->edid = edid;
+       if (!edid)
+               return 0;
+
+       drm_mode_connector_update_edid_property(connector, edid);
+       count = drm_add_edid_modes(connector, edid);
+
+       adv7511_set_config_csc(adv7511, connector, adv7511->rgb);
+
+       return count;
+}
+
+static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               adv7511->current_edid_segment = -1;
+
+               regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
+                            ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR);
+               regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
+                                  ADV7511_POWER_POWER_DOWN, 0);
+               /*
+                * Per spec it is allowed to pulse the HDP signal to indicate
+                * that the EDID information has changed. Some monitors do this
+                * when they wakeup from standby or are enabled. When the HDP
+                * goes low the adv7511 is reset and the outputs are disabled
+                * which might cause the monitor to go to standby again. To
+                * avoid this we ignore the HDP pin for the first few seconds
+                * after enabeling the output.
+                */
+               regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
+                                  ADV7511_REG_POWER2_HDP_SRC_MASK,
+                                  ADV7511_REG_POWER2_HDP_SRC_NONE);
+               /* Most of the registers are reset during power down or
+                * when HPD is low
+                */
+               regcache_sync(adv7511->regmap);
+               break;
+       default:
+               /* TODO: setup additional power down modes */
+               regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
+                                  ADV7511_POWER_POWER_DOWN,
+                                  ADV7511_POWER_POWER_DOWN);
+               regcache_mark_dirty(adv7511->regmap);
+               break;
+       }
+
+       adv7511->dpms_mode = mode;
+}
+
+static enum drm_connector_status
+adv7511_encoder_detect(struct drm_encoder *encoder,
+                      struct drm_connector *connector)
+{
+       struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+       enum drm_connector_status status;
+       unsigned int val;
+       bool hpd;
+       int ret;
+
+       ret = regmap_read(adv7511->regmap, ADV7511_REG_STATUS, &val);
+       if (ret < 0)
+               return connector_status_disconnected;
+
+       if (val & ADV7511_STATUS_HPD)
+               status = connector_status_connected;
+       else
+               status = connector_status_disconnected;
+
+       hpd = adv7511_hpd(adv7511);
+
+       /* The chip resets itself when the cable is disconnected, so in case
+        * there is a pending HPD interrupt and the cable is connected there was
+        * at least one transition from disconnected to connected and the chip
+        * has to be reinitialized. */
+       if (status == connector_status_connected && hpd &&
+           adv7511->dpms_mode == DRM_MODE_DPMS_ON) {
+               regcache_mark_dirty(adv7511->regmap);
+               adv7511_encoder_dpms(encoder, adv7511->dpms_mode);
+               adv7511_get_modes(encoder, connector);
+               if (adv7511->status == connector_status_connected)
+                       status = connector_status_disconnected;
+       } else {
+               /* Renable HDP sensing */
+               regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
+                                  ADV7511_REG_POWER2_HDP_SRC_MASK,
+                                  ADV7511_REG_POWER2_HDP_SRC_BOTH);
+       }
+
+       adv7511->status = status;
+       return status;
+}
+
+static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
+                                     struct drm_display_mode *mode)
+{
+       if (mode->clock > 165000)
+               return MODE_CLOCK_HIGH;
+
+       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+               return MODE_NO_INTERLACE;
+
+       return MODE_OK;
+}
+
+static void adv7511_encoder_mode_set(struct drm_encoder *encoder,
+                                    struct drm_display_mode *mode,
+                                    struct drm_display_mode *adj_mode)
+{
+       struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
+       unsigned int low_refresh_rate;
+       unsigned int hsync_polarity = 0;
+       unsigned int vsync_polarity = 0;
+
+       if (adv7511->embedded_sync) {
+               unsigned int hsync_offset, hsync_len;
+               unsigned int vsync_offset, vsync_len;
+
+               hsync_offset = adj_mode->crtc_hsync_start -
+                              adj_mode->crtc_hdisplay;
+               vsync_offset = adj_mode->crtc_vsync_start -
+                              adj_mode->crtc_vdisplay;
+               hsync_len = adj_mode->crtc_hsync_end -
+                           adj_mode->crtc_hsync_start;
+               vsync_len = adj_mode->crtc_vsync_end -
+                           adj_mode->crtc_vsync_start;
+
+               /* The hardware vsync generator has a off-by-one bug */
+               vsync_offset += 1;
+
+               regmap_write(adv7511->regmap, ADV7511_REG_HSYNC_PLACEMENT_MSB,
+                            ((hsync_offset >> 10) & 0x7) << 5);
+               regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(0),
+                            (hsync_offset >> 2) & 0xff);
+               regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(1),
+                            ((hsync_offset & 0x3) << 6) |
+                            ((hsync_len >> 4) & 0x3f));
+               regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(2),
+                            ((hsync_len & 0xf) << 4) |
+                            ((vsync_offset >> 6) & 0xf));
+               regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(3),
+                            ((vsync_offset & 0x3f) << 2) |
+                            ((vsync_len >> 8) & 0x3));
+               regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(4),
+                            vsync_len & 0xff);
+
+               hsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PHSYNC);
+               vsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PVSYNC);
+       } else {
+               enum adv7511_sync_polarity mode_hsync_polarity;
+               enum adv7511_sync_polarity mode_vsync_polarity;
+
+               /**
+                * If the input signal is always low or always high we want to
+                * invert or let it passthrough depending on the polarity of the
+                * current mode.
+                **/
+               if (adj_mode->flags & DRM_MODE_FLAG_NHSYNC)
+                       mode_hsync_polarity = ADV7511_SYNC_POLARITY_LOW;
+               else
+                       mode_hsync_polarity = ADV7511_SYNC_POLARITY_HIGH;
+
+               if (adj_mode->flags & DRM_MODE_FLAG_NVSYNC)
+                       mode_vsync_polarity = ADV7511_SYNC_POLARITY_LOW;
+               else
+                       mode_vsync_polarity = ADV7511_SYNC_POLARITY_HIGH;
+
+               if (adv7511->hsync_polarity != mode_hsync_polarity &&
+                   adv7511->hsync_polarity !=
+                   ADV7511_SYNC_POLARITY_PASSTHROUGH)
+                       hsync_polarity = 1;
+
+               if (adv7511->vsync_polarity != mode_vsync_polarity &&
+                   adv7511->vsync_polarity !=
+                   ADV7511_SYNC_POLARITY_PASSTHROUGH)
+                       vsync_polarity = 1;
+       }
+
+       if (mode->vrefresh <= 24000)
+               low_refresh_rate = ADV7511_LOW_REFRESH_RATE_24HZ;
+       else if (mode->vrefresh <= 25000)
+               low_refresh_rate = ADV7511_LOW_REFRESH_RATE_25HZ;
+       else if (mode->vrefresh <= 30000)
+               low_refresh_rate = ADV7511_LOW_REFRESH_RATE_30HZ;
+       else
+               low_refresh_rate = ADV7511_LOW_REFRESH_RATE_NONE;
+
+       regmap_update_bits(adv7511->regmap, 0xfb,
+               0x6, low_refresh_rate << 1);
+       regmap_update_bits(adv7511->regmap, 0x17,
+               0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
+
+       /*
+        * TODO Test first order 4:2:2 to 4:4:4 up conversion method, which is
+        * supposed to give better results.
+        */
+
+       adv7511->f_tmds = mode->clock;
+}
+
+static struct drm_encoder_slave_funcs adv7511_encoder_funcs = {
+       .dpms = adv7511_encoder_dpms,
+       .mode_valid = adv7511_encoder_mode_valid,
+       .mode_set = adv7511_encoder_mode_set,
+       .detect = adv7511_encoder_detect,
+       .get_modes = adv7511_get_modes,
+};
+
+/* -----------------------------------------------------------------------------
+ * Probe & remove
+ */
+
+static int adv7511_parse_dt(struct device_node *np,
+                           struct adv7511_link_config *config)
+{
+       const char *str;
+       int ret;
+
+       memset(config, 0, sizeof(*config));
+
+       of_property_read_u32(np, "adi,input-depth", &config->input_color_depth);
+       if (config->input_color_depth != 8 && config->input_color_depth != 10 &&
+           config->input_color_depth != 12)
+               return -EINVAL;
+
+       ret = of_property_read_string(np, "adi,input-colorspace", &str);
+       if (ret < 0)
+               return ret;
+
+       if (!strcmp(str, "rgb"))
+               config->input_colorspace = HDMI_COLORSPACE_RGB;
+       else if (!strcmp(str, "yuv422"))
+               config->input_colorspace = HDMI_COLORSPACE_YUV422;
+       else if (!strcmp(str, "yuv444"))
+               config->input_colorspace = HDMI_COLORSPACE_YUV444;
+       else
+               return -EINVAL;
+
+       ret = of_property_read_string(np, "adi,input-clock", &str);
+       if (ret < 0)
+               return ret;
+
+       if (!strcmp(str, "1x"))
+               config->input_clock = ADV7511_INPUT_CLOCK_1X;
+       else if (!strcmp(str, "2x"))
+               config->input_clock = ADV7511_INPUT_CLOCK_2X;
+       else if (!strcmp(str, "ddr"))
+               config->input_clock = ADV7511_INPUT_CLOCK_DDR;
+       else
+               return -EINVAL;
+
+       if (config->input_colorspace == HDMI_COLORSPACE_YUV422 ||
+           config->input_clock != ADV7511_INPUT_CLOCK_1X) {
+               ret = of_property_read_u32(np, "adi,input-style",
+                                          &config->input_style);
+               if (ret)
+                       return ret;
+
+               if (config->input_style < 1 || config->input_style > 3)
+                       return -EINVAL;
+
+               ret = of_property_read_string(np, "adi,input-justification",
+                                             &str);
+               if (ret < 0)
+                       return ret;
+
+               if (!strcmp(str, "left"))
+                       config->input_justification =
+                               ADV7511_INPUT_JUSTIFICATION_LEFT;
+               else if (!strcmp(str, "evenly"))
+                       config->input_justification =
+                               ADV7511_INPUT_JUSTIFICATION_EVENLY;
+               else if (!strcmp(str, "right"))
+                       config->input_justification =
+                               ADV7511_INPUT_JUSTIFICATION_RIGHT;
+               else
+                       return -EINVAL;
+
+       } else {
+               config->input_style = 1;
+               config->input_justification = ADV7511_INPUT_JUSTIFICATION_LEFT;
+       }
+
+       of_property_read_u32(np, "adi,clock-delay", &config->clock_delay);
+       if (config->clock_delay < -1200 || config->clock_delay > 1600)
+               return -EINVAL;
+
+       config->embedded_sync = of_property_read_bool(np, "adi,embedded-sync");
+
+       /* Hardcode the sync pulse configurations for now. */
+       config->sync_pulse = ADV7511_INPUT_SYNC_PULSE_NONE;
+       config->vsync_polarity = ADV7511_SYNC_POLARITY_PASSTHROUGH;
+       config->hsync_polarity = ADV7511_SYNC_POLARITY_PASSTHROUGH;
+
+       return 0;
+}
+
+static const int edid_i2c_addr = 0x7e;
+static const int packet_i2c_addr = 0x70;
+static const int cec_i2c_addr = 0x78;
+
+static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+       struct adv7511_link_config link_config;
+       struct adv7511 *adv7511;
+       struct device *dev = &i2c->dev;
+       unsigned int val;
+       int ret;
+
+       if (!dev->of_node)
+               return -EINVAL;
+
+       adv7511 = devm_kzalloc(dev, sizeof(*adv7511), GFP_KERNEL);
+       if (!adv7511)
+               return -ENOMEM;
+
+       adv7511->dpms_mode = DRM_MODE_DPMS_OFF;
+       adv7511->status = connector_status_disconnected;
+
+       ret = adv7511_parse_dt(dev->of_node, &link_config);
+       if (ret)
+               return ret;
+
+       /*
+        * The power down GPIO is optional. If present, toggle it from active to
+        * inactive to wake up the encoder.
+        */
+       adv7511->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH);
+       if (IS_ERR(adv7511->gpio_pd))
+               return PTR_ERR(adv7511->gpio_pd);
+
+       if (adv7511->gpio_pd) {
+               mdelay(5);
+               gpiod_set_value_cansleep(adv7511->gpio_pd, 0);
+       }
+
+       adv7511->regmap = devm_regmap_init_i2c(i2c, &adv7511_regmap_config);
+       if (IS_ERR(adv7511->regmap))
+               return PTR_ERR(adv7511->regmap);
+
+       ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val);
+       if (ret)
+               return ret;
+       dev_dbg(dev, "Rev. %d\n", val);
+
+       ret = regmap_register_patch(adv7511->regmap, adv7511_fixed_registers,
+                                   ARRAY_SIZE(adv7511_fixed_registers));
+       if (ret)
+               return ret;
+
+       regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr);
+       regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
+                    packet_i2c_addr);
+       regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR, cec_i2c_addr);
+       adv7511_packet_disable(adv7511, 0xffff);
+
+       adv7511->i2c_main = i2c;
+       adv7511->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1);
+       if (!adv7511->i2c_edid)
+               return -ENOMEM;
+
+       if (i2c->irq) {
+               init_waitqueue_head(&adv7511->wq);
+
+               ret = devm_request_threaded_irq(dev, i2c->irq, NULL,
+                                               adv7511_irq_handler,
+                                               IRQF_ONESHOT, dev_name(dev),
+                                               adv7511);
+               if (ret)
+                       goto err_i2c_unregister_device;
+       }
+
+       /* CEC is unused for now */
+       regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL,
+                    ADV7511_CEC_CTRL_POWER_DOWN);
+
+       regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
+                          ADV7511_POWER_POWER_DOWN, ADV7511_POWER_POWER_DOWN);
+
+       adv7511->current_edid_segment = -1;
+
+       i2c_set_clientdata(i2c, adv7511);
+
+       adv7511_set_link_config(adv7511, &link_config);
+
+       return 0;
+
+err_i2c_unregister_device:
+       i2c_unregister_device(adv7511->i2c_edid);
+
+       return ret;
+}
+
+static int adv7511_remove(struct i2c_client *i2c)
+{
+       struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
+
+       i2c_unregister_device(adv7511->i2c_edid);
+
+       kfree(adv7511->edid);
+
+       return 0;
+}
+
+static int adv7511_encoder_init(struct i2c_client *i2c, struct drm_device *dev,
+                               struct drm_encoder_slave *encoder)
+{
+
+       struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
+
+       encoder->slave_priv = adv7511;
+       encoder->slave_funcs = &adv7511_encoder_funcs;
+
+       adv7511->encoder = &encoder->base;
+
+       return 0;
+}
+
+static const struct i2c_device_id adv7511_i2c_ids[] = {
+       { "adv7511", 0 },
+       { "adv7511w", 0 },
+       { "adv7513", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adv7511_i2c_ids);
+
+static const struct of_device_id adv7511_of_ids[] = {
+       { .compatible = "adi,adv7511", },
+       { .compatible = "adi,adv7511w", },
+       { .compatible = "adi,adv7513", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, adv7511_of_ids);
+
+static struct drm_i2c_encoder_driver adv7511_driver = {
+       .i2c_driver = {
+               .driver = {
+                       .name = "adv7511",
+                       .of_match_table = adv7511_of_ids,
+               },
+               .id_table = adv7511_i2c_ids,
+               .probe = adv7511_probe,
+               .remove = adv7511_remove,
+       },
+
+       .encoder_init = adv7511_encoder_init,
+};
+
+static int __init adv7511_init(void)
+{
+       return drm_i2c_encoder_register(THIS_MODULE, &adv7511_driver);
+}
+module_init(adv7511_init);
+
+static void __exit adv7511_exit(void)
+{
+       drm_i2c_encoder_unregister(&adv7511_driver);
+}
+module_exit(adv7511_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/i2c/adv7511.h b/drivers/gpu/drm/i2c/adv7511.h
new file mode 100644 (file)
index 0000000..6599ed5
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Analog Devices ADV7511 HDMI transmitter driver
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __DRM_I2C_ADV7511_H__
+#define __DRM_I2C_ADV7511_H__
+
+#include <linux/hdmi.h>
+
+#define ADV7511_REG_CHIP_REVISION              0x00
+#define ADV7511_REG_N0                         0x01
+#define ADV7511_REG_N1                         0x02
+#define ADV7511_REG_N2                         0x03
+#define ADV7511_REG_SPDIF_FREQ                 0x04
+#define ADV7511_REG_CTS_AUTOMATIC1             0x05
+#define ADV7511_REG_CTS_AUTOMATIC2             0x06
+#define ADV7511_REG_CTS_MANUAL0                        0x07
+#define ADV7511_REG_CTS_MANUAL1                        0x08
+#define ADV7511_REG_CTS_MANUAL2                        0x09
+#define ADV7511_REG_AUDIO_SOURCE               0x0a
+#define ADV7511_REG_AUDIO_CONFIG               0x0b
+#define ADV7511_REG_I2S_CONFIG                 0x0c
+#define ADV7511_REG_I2S_WIDTH                  0x0d
+#define ADV7511_REG_AUDIO_SUB_SRC0             0x0e
+#define ADV7511_REG_AUDIO_SUB_SRC1             0x0f
+#define ADV7511_REG_AUDIO_SUB_SRC2             0x10
+#define ADV7511_REG_AUDIO_SUB_SRC3             0x11
+#define ADV7511_REG_AUDIO_CFG1                 0x12
+#define ADV7511_REG_AUDIO_CFG2                 0x13
+#define ADV7511_REG_AUDIO_CFG3                 0x14
+#define ADV7511_REG_I2C_FREQ_ID_CFG            0x15
+#define ADV7511_REG_VIDEO_INPUT_CFG1           0x16
+#define ADV7511_REG_CSC_UPPER(x)               (0x18 + (x) * 2)
+#define ADV7511_REG_CSC_LOWER(x)               (0x19 + (x) * 2)
+#define ADV7511_REG_SYNC_DECODER(x)            (0x30 + (x))
+#define ADV7511_REG_DE_GENERATOR               (0x35 + (x))
+#define ADV7511_REG_PIXEL_REPETITION           0x3b
+#define ADV7511_REG_VIC_MANUAL                 0x3c
+#define ADV7511_REG_VIC_SEND                   0x3d
+#define ADV7511_REG_VIC_DETECTED               0x3e
+#define ADV7511_REG_AUX_VIC_DETECTED           0x3f
+#define ADV7511_REG_PACKET_ENABLE0             0x40
+#define ADV7511_REG_POWER                      0x41
+#define ADV7511_REG_STATUS                     0x42
+#define ADV7511_REG_EDID_I2C_ADDR              0x43
+#define ADV7511_REG_PACKET_ENABLE1             0x44
+#define ADV7511_REG_PACKET_I2C_ADDR            0x45
+#define ADV7511_REG_DSD_ENABLE                 0x46
+#define ADV7511_REG_VIDEO_INPUT_CFG2           0x48
+#define ADV7511_REG_INFOFRAME_UPDATE           0x4a
+#define ADV7511_REG_GC(x)                      (0x4b + (x)) /* 0x4b - 0x51 */
+#define ADV7511_REG_AVI_INFOFRAME_VERSION      0x52
+#define ADV7511_REG_AVI_INFOFRAME_LENGTH       0x53
+#define ADV7511_REG_AVI_INFOFRAME_CHECKSUM     0x54
+#define ADV7511_REG_AVI_INFOFRAME(x)           (0x55 + (x)) /* 0x55 - 0x6f */
+#define ADV7511_REG_AUDIO_INFOFRAME_VERSION    0x70
+#define ADV7511_REG_AUDIO_INFOFRAME_LENGTH     0x71
+#define ADV7511_REG_AUDIO_INFOFRAME_CHECKSUM   0x72
+#define ADV7511_REG_AUDIO_INFOFRAME(x)         (0x73 + (x)) /* 0x73 - 0x7c */
+#define ADV7511_REG_INT_ENABLE(x)              (0x94 + (x))
+#define ADV7511_REG_INT(x)                     (0x96 + (x))
+#define ADV7511_REG_INPUT_CLK_DIV              0x9d
+#define ADV7511_REG_PLL_STATUS                 0x9e
+#define ADV7511_REG_HDMI_POWER                 0xa1
+#define ADV7511_REG_HDCP_HDMI_CFG              0xaf
+#define ADV7511_REG_AN(x)                      (0xb0 + (x)) /* 0xb0 - 0xb7 */
+#define ADV7511_REG_HDCP_STATUS                        0xb8
+#define ADV7511_REG_BCAPS                      0xbe
+#define ADV7511_REG_BKSV(x)                    (0xc0 + (x)) /* 0xc0 - 0xc3 */
+#define ADV7511_REG_EDID_SEGMENT               0xc4
+#define ADV7511_REG_DDC_STATUS                 0xc8
+#define ADV7511_REG_EDID_READ_CTRL             0xc9
+#define ADV7511_REG_BSTATUS(x)                 (0xca + (x)) /* 0xca - 0xcb */
+#define ADV7511_REG_TIMING_GEN_SEQ             0xd0
+#define ADV7511_REG_POWER2                     0xd6
+#define ADV7511_REG_HSYNC_PLACEMENT_MSB                0xfa
+
+#define ADV7511_REG_SYNC_ADJUSTMENT(x)         (0xd7 + (x)) /* 0xd7 - 0xdc */
+#define ADV7511_REG_TMDS_CLOCK_INV             0xde
+#define ADV7511_REG_ARC_CTRL                   0xdf
+#define ADV7511_REG_CEC_I2C_ADDR               0xe1
+#define ADV7511_REG_CEC_CTRL                   0xe2
+#define ADV7511_REG_CHIP_ID_HIGH               0xf5
+#define ADV7511_REG_CHIP_ID_LOW                        0xf6
+
+#define ADV7511_CSC_ENABLE                     BIT(7)
+#define ADV7511_CSC_UPDATE_MODE                        BIT(5)
+
+#define ADV7511_INT0_HDP                       BIT(7)
+#define ADV7511_INT0_VSYNC                     BIT(5)
+#define ADV7511_INT0_AUDIO_FIFO_FULL           BIT(4)
+#define ADV7511_INT0_EDID_READY                        BIT(2)
+#define ADV7511_INT0_HDCP_AUTHENTICATED                BIT(1)
+
+#define ADV7511_INT1_DDC_ERROR                 BIT(7)
+#define ADV7511_INT1_BKSV                      BIT(6)
+#define ADV7511_INT1_CEC_TX_READY              BIT(5)
+#define ADV7511_INT1_CEC_TX_ARBIT_LOST         BIT(4)
+#define ADV7511_INT1_CEC_TX_RETRY_TIMEOUT      BIT(3)
+#define ADV7511_INT1_CEC_RX_READY3             BIT(2)
+#define ADV7511_INT1_CEC_RX_READY2             BIT(1)
+#define ADV7511_INT1_CEC_RX_READY1             BIT(0)
+
+#define ADV7511_ARC_CTRL_POWER_DOWN            BIT(0)
+
+#define ADV7511_CEC_CTRL_POWER_DOWN            BIT(0)
+
+#define ADV7511_POWER_POWER_DOWN               BIT(6)
+
+#define ADV7511_HDMI_CFG_MODE_MASK             0x2
+#define ADV7511_HDMI_CFG_MODE_DVI              0x0
+#define ADV7511_HDMI_CFG_MODE_HDMI             0x2
+
+#define ADV7511_AUDIO_SELECT_I2C               0x0
+#define ADV7511_AUDIO_SELECT_SPDIF             0x1
+#define ADV7511_AUDIO_SELECT_DSD               0x2
+#define ADV7511_AUDIO_SELECT_HBR               0x3
+#define ADV7511_AUDIO_SELECT_DST               0x4
+
+#define ADV7511_I2S_SAMPLE_LEN_16              0x2
+#define ADV7511_I2S_SAMPLE_LEN_20              0x3
+#define ADV7511_I2S_SAMPLE_LEN_18              0x4
+#define ADV7511_I2S_SAMPLE_LEN_22              0x5
+#define ADV7511_I2S_SAMPLE_LEN_19              0x8
+#define ADV7511_I2S_SAMPLE_LEN_23              0x9
+#define ADV7511_I2S_SAMPLE_LEN_24              0xb
+#define ADV7511_I2S_SAMPLE_LEN_17              0xc
+#define ADV7511_I2S_SAMPLE_LEN_21              0xd
+
+#define ADV7511_SAMPLE_FREQ_44100              0x0
+#define ADV7511_SAMPLE_FREQ_48000              0x2
+#define ADV7511_SAMPLE_FREQ_32000              0x3
+#define ADV7511_SAMPLE_FREQ_88200              0x8
+#define ADV7511_SAMPLE_FREQ_96000              0xa
+#define ADV7511_SAMPLE_FREQ_176400             0xc
+#define ADV7511_SAMPLE_FREQ_192000             0xe
+
+#define ADV7511_STATUS_POWER_DOWN_POLARITY     BIT(7)
+#define ADV7511_STATUS_HPD                     BIT(6)
+#define ADV7511_STATUS_MONITOR_SENSE           BIT(5)
+#define ADV7511_STATUS_I2S_32BIT_MODE          BIT(3)
+
+#define ADV7511_PACKET_ENABLE_N_CTS            BIT(8+6)
+#define ADV7511_PACKET_ENABLE_AUDIO_SAMPLE     BIT(8+5)
+#define ADV7511_PACKET_ENABLE_AVI_INFOFRAME    BIT(8+4)
+#define ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME  BIT(8+3)
+#define ADV7511_PACKET_ENABLE_GC               BIT(7)
+#define ADV7511_PACKET_ENABLE_SPD              BIT(6)
+#define ADV7511_PACKET_ENABLE_MPEG             BIT(5)
+#define ADV7511_PACKET_ENABLE_ACP              BIT(4)
+#define ADV7511_PACKET_ENABLE_ISRC             BIT(3)
+#define ADV7511_PACKET_ENABLE_GM               BIT(2)
+#define ADV7511_PACKET_ENABLE_SPARE2           BIT(1)
+#define ADV7511_PACKET_ENABLE_SPARE1           BIT(0)
+
+#define ADV7511_REG_POWER2_HDP_SRC_MASK                0xc0
+#define ADV7511_REG_POWER2_HDP_SRC_BOTH                0x00
+#define ADV7511_REG_POWER2_HDP_SRC_HDP         0x40
+#define ADV7511_REG_POWER2_HDP_SRC_CEC         0x80
+#define ADV7511_REG_POWER2_HDP_SRC_NONE                0xc0
+#define ADV7511_REG_POWER2_TDMS_ENABLE         BIT(4)
+#define ADV7511_REG_POWER2_GATE_INPUT_CLK      BIT(0)
+
+#define ADV7511_LOW_REFRESH_RATE_NONE          0x0
+#define ADV7511_LOW_REFRESH_RATE_24HZ          0x1
+#define ADV7511_LOW_REFRESH_RATE_25HZ          0x2
+#define ADV7511_LOW_REFRESH_RATE_30HZ          0x3
+
+#define ADV7511_AUDIO_CFG3_LEN_MASK            0x0f
+#define ADV7511_I2C_FREQ_ID_CFG_RATE_MASK      0xf0
+
+#define ADV7511_AUDIO_SOURCE_I2S               0
+#define ADV7511_AUDIO_SOURCE_SPDIF             1
+
+#define ADV7511_I2S_FORMAT_I2S                 0
+#define ADV7511_I2S_FORMAT_RIGHT_J             1
+#define ADV7511_I2S_FORMAT_LEFT_J              2
+
+#define ADV7511_PACKET(p, x)       ((p) * 0x20 + (x))
+#define ADV7511_PACKET_SDP(x)      ADV7511_PACKET(0, x)
+#define ADV7511_PACKET_MPEG(x)     ADV7511_PACKET(1, x)
+#define ADV7511_PACKET_ACP(x)      ADV7511_PACKET(2, x)
+#define ADV7511_PACKET_ISRC1(x)            ADV7511_PACKET(3, x)
+#define ADV7511_PACKET_ISRC2(x)            ADV7511_PACKET(4, x)
+#define ADV7511_PACKET_GM(x)       ADV7511_PACKET(5, x)
+#define ADV7511_PACKET_SPARE(x)            ADV7511_PACKET(6, x)
+
+enum adv7511_input_clock {
+       ADV7511_INPUT_CLOCK_1X,
+       ADV7511_INPUT_CLOCK_2X,
+       ADV7511_INPUT_CLOCK_DDR,
+};
+
+enum adv7511_input_justification {
+       ADV7511_INPUT_JUSTIFICATION_EVENLY = 0,
+       ADV7511_INPUT_JUSTIFICATION_RIGHT = 1,
+       ADV7511_INPUT_JUSTIFICATION_LEFT = 2,
+};
+
+enum adv7511_input_sync_pulse {
+       ADV7511_INPUT_SYNC_PULSE_DE = 0,
+       ADV7511_INPUT_SYNC_PULSE_HSYNC = 1,
+       ADV7511_INPUT_SYNC_PULSE_VSYNC = 2,
+       ADV7511_INPUT_SYNC_PULSE_NONE = 3,
+};
+
+/**
+ * enum adv7511_sync_polarity - Polarity for the input sync signals
+ * @ADV7511_SYNC_POLARITY_PASSTHROUGH:  Sync polarity matches that of
+ *                                    the currently configured mode.
+ * @ADV7511_SYNC_POLARITY_LOW:     Sync polarity is low
+ * @ADV7511_SYNC_POLARITY_HIGH:            Sync polarity is high
+ *
+ * If the polarity is set to either LOW or HIGH the driver will configure the
+ * ADV7511 to internally invert the sync signal if required to match the sync
+ * polarity setting for the currently selected output mode.
+ *
+ * If the polarity is set to PASSTHROUGH, the ADV7511 will route the signal
+ * unchanged. This is used when the upstream graphics core already generates
+ * the sync signals with the correct polarity.
+ */
+enum adv7511_sync_polarity {
+       ADV7511_SYNC_POLARITY_PASSTHROUGH,
+       ADV7511_SYNC_POLARITY_LOW,
+       ADV7511_SYNC_POLARITY_HIGH,
+};
+
+/**
+ * struct adv7511_link_config - Describes adv7511 hardware configuration
+ * @input_color_depth:         Number of bits per color component (8, 10 or 12)
+ * @input_colorspace:          The input colorspace (RGB, YUV444, YUV422)
+ * @input_clock:               The input video clock style (1x, 2x, DDR)
+ * @input_style:               The input component arrangement variant
+ * @input_justification:       Video input format bit justification
+ * @clock_delay:               Clock delay for the input clock (in ps)
+ * @embedded_sync:             Video input uses BT.656-style embedded sync
+ * @sync_pulse:                        Select the sync pulse
+ * @vsync_polarity:            vsync input signal configuration
+ * @hsync_polarity:            hsync input signal configuration
+ */
+struct adv7511_link_config {
+       unsigned int input_color_depth;
+       enum hdmi_colorspace input_colorspace;
+       enum adv7511_input_clock input_clock;
+       unsigned int input_style;
+       enum adv7511_input_justification input_justification;
+
+       int clock_delay;
+
+       bool embedded_sync;
+       enum adv7511_input_sync_pulse sync_pulse;
+       enum adv7511_sync_polarity vsync_polarity;
+       enum adv7511_sync_polarity hsync_polarity;
+};
+
+/**
+ * enum adv7511_csc_scaling - Scaling factor for the ADV7511 CSC
+ * @ADV7511_CSC_SCALING_1: CSC results are not scaled
+ * @ADV7511_CSC_SCALING_2: CSC results are scaled by a factor of two
+ * @ADV7511_CSC_SCALING_4: CSC results are scalled by a factor of four
+ */
+enum adv7511_csc_scaling {
+       ADV7511_CSC_SCALING_1 = 0,
+       ADV7511_CSC_SCALING_2 = 1,
+       ADV7511_CSC_SCALING_4 = 2,
+};
+
+/**
+ * struct adv7511_video_config - Describes adv7511 hardware configuration
+ * @csc_enable:                        Whether to enable color space conversion
+ * @csc_scaling_factor:                Color space conversion scaling factor
+ * @csc_coefficents:           Color space conversion coefficents
+ * @hdmi_mode:                 Whether to use HDMI or DVI output mode
+ * @avi_infoframe:             HDMI infoframe
+ */
+struct adv7511_video_config {
+       bool csc_enable;
+       enum adv7511_csc_scaling csc_scaling_factor;
+       const uint16_t *csc_coefficents;
+
+       bool hdmi_mode;
+       struct hdmi_avi_infoframe avi_infoframe;
+};
+
+#endif /* __DRM_I2C_ADV7511_H__ */
index 1df4079417006b72d2b66dbc6ae80d24b5d41925..1e9c136a874cf1741e09aecc33c6cea37e26e1d4 100644 (file)
@@ -1583,7 +1583,7 @@ static struct drm_driver driver = {
        .gem_prime_import = i915_gem_prime_import,
 
        .dumb_create = i915_gem_dumb_create,
-       .dumb_map_offset = i915_gem_mmap_gtt,
+       .dumb_map_offset = i915_gem_dumb_map_offset,
        .dumb_destroy = drm_gem_dumb_destroy,
        .ioctls = i915_ioctls,
        .fops = &i915_driver_fops,
index b6d8d2dce20338cab5562536944f9aaecda7564a..bb1892d72efefe14bf78ce4633405d51e2251b32 100644 (file)
@@ -2500,8 +2500,9 @@ void i915_vma_move_to_active(struct i915_vma *vma,
 int i915_gem_dumb_create(struct drm_file *file_priv,
                         struct drm_device *dev,
                         struct drm_mode_create_dumb *args);
-int i915_gem_mmap_gtt(struct drm_file *file_priv, struct drm_device *dev,
-                     uint32_t handle, uint64_t *offset);
+int i915_gem_dumb_map_offset(struct drm_file *file_priv,
+                            struct drm_device *dev, uint32_t handle,
+                            uint64_t *offset);
 /**
  * Returns true if seq1 is later than seq2.
  */
index 3c64eb6abf2d71084003ab43b6fb7467ac93cf92..fd17ccabd8a496242bafd767a932a80af6593008 100644 (file)
@@ -401,6 +401,7 @@ static int
 i915_gem_create(struct drm_file *file,
                struct drm_device *dev,
                uint64_t size,
+               bool dumb,
                uint32_t *handle_p)
 {
        struct drm_i915_gem_object *obj;
@@ -416,6 +417,7 @@ i915_gem_create(struct drm_file *file,
        if (obj == NULL)
                return -ENOMEM;
 
+       obj->base.dumb = dumb;
        ret = drm_gem_handle_create(file, &obj->base, &handle);
        /* drop reference from allocate - handle holds it now */
        drm_gem_object_unreference_unlocked(&obj->base);
@@ -435,7 +437,7 @@ i915_gem_dumb_create(struct drm_file *file,
        args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 64);
        args->size = args->pitch * args->height;
        return i915_gem_create(file, dev,
-                              args->size, &args->handle);
+                              args->size, true, &args->handle);
 }
 
 /**
@@ -448,7 +450,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
        struct drm_i915_gem_create *args = data;
 
        return i915_gem_create(file, dev,
-                              args->size, &args->handle);
+                              args->size, false, &args->handle);
 }
 
 static inline int
@@ -1827,10 +1829,10 @@ static void i915_gem_object_free_mmap_offset(struct drm_i915_gem_object *obj)
        drm_gem_free_mmap_offset(&obj->base);
 }
 
-int
+static int
 i915_gem_mmap_gtt(struct drm_file *file,
                  struct drm_device *dev,
-                 uint32_t handle,
+                 uint32_t handle, bool dumb,
                  uint64_t *offset)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1847,6 +1849,13 @@ i915_gem_mmap_gtt(struct drm_file *file,
                goto unlock;
        }
 
+       /*
+        * We don't allow dumb mmaps on objects created using another
+        * interface.
+        */
+       WARN_ONCE(dumb && !(obj->base.dumb || obj->base.import_attach),
+                 "Illegal dumb map of accelerated buffer.\n");
+
        if (obj->base.size > dev_priv->gtt.mappable_end) {
                ret = -E2BIG;
                goto out;
@@ -1871,6 +1880,15 @@ unlock:
        return ret;
 }
 
+int
+i915_gem_dumb_map_offset(struct drm_file *file,
+                        struct drm_device *dev,
+                        uint32_t handle,
+                        uint64_t *offset)
+{
+       return i915_gem_mmap_gtt(file, dev, handle, true, offset);
+}
+
 /**
  * i915_gem_mmap_gtt_ioctl - prepare an object for GTT mmap'ing
  * @dev: DRM device
@@ -1892,7 +1910,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
 {
        struct drm_i915_gem_mmap_gtt *args = data;
 
-       return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset);
+       return i915_gem_mmap_gtt(file, dev, args->handle, false, &args->offset);
 }
 
 static inline int
index 11738316394af9b16669155dbbec74fde0f22223..f06027ba3ee5512a7718deb22112f9fe6e16458b 100644 (file)
@@ -121,6 +121,9 @@ eb_lookup_vmas(struct eb_vmas *eb,
                        goto err;
                }
 
+               WARN_ONCE(obj->base.dumb,
+                         "GPU use of dumb buffer is illegal.\n");
+
                drm_gem_object_reference(&obj->base);
                list_add_tail(&obj->obj_exec_link, &objects);
        }
index d4aa2dd5f14d0acd874d110c143bb93e2c20f012..853697fc4d4b7f96d474e30da9594d53f49a4e8e 100644 (file)
@@ -8619,6 +8619,9 @@ retry:
                crtc = encoder->crtc;
 
                ret = drm_modeset_lock(&crtc->mutex, ctx);
+               if (ret)
+                       goto fail_unlock;
+               ret = drm_modeset_lock(&crtc->primary->mutex, ctx);
                if (ret)
                        goto fail_unlock;
 
@@ -8656,6 +8659,9 @@ retry:
        }
 
        ret = drm_modeset_lock(&crtc->mutex, ctx);
+       if (ret)
+               goto fail_unlock;
+       ret = drm_modeset_lock(&crtc->primary->mutex, ctx);
        if (ret)
                goto fail_unlock;
        intel_encoder->new_crtc = to_intel_crtc(crtc);
@@ -9117,6 +9123,10 @@ static bool page_flip_finished(struct intel_crtc *crtc)
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       if (i915_reset_in_progress(&dev_priv->gpu_error) ||
+           crtc->reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter))
+               return true;
+
        /*
         * The relevant registers doen't exist on pre-ctg.
         * As the flip done interrupt doesn't trigger for mmio
index 46731da407c04858c07da44fe85d49c3c38aef9f..d2529ec280c8207b34b0bcbea5a9588003d50bc0 100644 (file)
@@ -4335,6 +4335,7 @@ static void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
         * vdd might still be enabled do to the delayed vdd off.
         * Make sure vdd is actually turned off here.
         */
+       cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
        pps_lock(intel_dp);
        edp_panel_vdd_off_sync(intel_dp);
        pps_unlock(intel_dp);
index b03fa9026a9c8936e891a12fa43cd9360399b4ce..bfe359506377852154b43c0307fb7e61c300277c 100644 (file)
@@ -385,7 +385,7 @@ static void intel_connector_remove_from_fbdev(struct intel_connector *connector)
 #endif
 }
 
-static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, char *pathprop)
+static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, const char *pathprop)
 {
        struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst_mgr);
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig
new file mode 100644 (file)
index 0000000..82fb758
--- /dev/null
@@ -0,0 +1,53 @@
+config DRM_IMX
+       tristate "DRM Support for Freescale i.MX"
+       select DRM_KMS_HELPER
+       select DRM_KMS_FB_HELPER
+       select VIDEOMODE_HELPERS
+       select DRM_GEM_CMA_HELPER
+       select DRM_KMS_CMA_HELPER
+       depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM)
+       help
+         enable i.MX graphics support
+
+config DRM_IMX_FB_HELPER
+       tristate "provide legacy framebuffer /dev/fb0"
+       select DRM_KMS_CMA_HELPER
+       depends on DRM_IMX
+       help
+         The DRM framework can provide a legacy /dev/fb0 framebuffer
+         for your device. This is necessary to get a framebuffer console
+         and also for applications using the legacy framebuffer API
+
+config DRM_IMX_PARALLEL_DISPLAY
+       tristate "Support for parallel displays"
+       select DRM_PANEL
+       depends on DRM_IMX
+       select VIDEOMODE_HELPERS
+
+config DRM_IMX_TVE
+       tristate "Support for TV and VGA displays"
+       depends on DRM_IMX
+       select REGMAP_MMIO
+       help
+         Choose this to enable the internal Television Encoder (TVe)
+         found on i.MX53 processors.
+
+config DRM_IMX_LDB
+       tristate "Support for LVDS displays"
+       depends on DRM_IMX && MFD_SYSCON
+       help
+         Choose this to enable the internal LVDS Display Bridge (LDB)
+         found on i.MX53 and i.MX6 processors.
+
+config DRM_IMX_IPUV3
+       tristate "DRM Support for i.MX IPUv3"
+       depends on DRM_IMX
+       depends on IMX_IPUV3_CORE
+       help
+         Choose this if you have a i.MX5 or i.MX6 processor.
+
+config DRM_IMX_HDMI
+       tristate "Freescale i.MX DRM HDMI"
+       depends on DRM_IMX
+       help
+         Choose this if you want to use HDMI on i.MX6.
diff --git a/drivers/gpu/drm/imx/Makefile b/drivers/gpu/drm/imx/Makefile
new file mode 100644 (file)
index 0000000..582c438
--- /dev/null
@@ -0,0 +1,12 @@
+
+imxdrm-objs := imx-drm-core.o
+
+obj-$(CONFIG_DRM_IMX) += imxdrm.o
+
+obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
+obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
+obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
+
+imx-ipuv3-crtc-objs  := ipuv3-crtc.o ipuv3-plane.o
+obj-$(CONFIG_DRM_IMX_IPUV3)    += imx-ipuv3-crtc.o
+obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
new file mode 100644 (file)
index 0000000..2f80072
--- /dev/null
@@ -0,0 +1,705 @@
+/*
+ * Freescale i.MX drm driver
+ *
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix
+ *
+ * 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/component.h>
+#include <linux/device.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_plane_helper.h>
+
+#include "imx-drm.h"
+
+#define MAX_CRTC       4
+
+struct imx_drm_crtc;
+
+struct imx_drm_component {
+       struct device_node *of_node;
+       struct list_head list;
+};
+
+struct imx_drm_device {
+       struct drm_device                       *drm;
+       struct imx_drm_crtc                     *crtc[MAX_CRTC];
+       int                                     pipes;
+       struct drm_fbdev_cma                    *fbhelper;
+};
+
+struct imx_drm_crtc {
+       struct drm_crtc                         *crtc;
+       int                                     pipe;
+       struct imx_drm_crtc_helper_funcs        imx_drm_helper_funcs;
+       struct device_node                      *port;
+};
+
+static int legacyfb_depth = 16;
+module_param(legacyfb_depth, int, 0444);
+
+int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
+{
+       return crtc->pipe;
+}
+EXPORT_SYMBOL_GPL(imx_drm_crtc_id);
+
+static void imx_drm_driver_lastclose(struct drm_device *drm)
+{
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+       struct imx_drm_device *imxdrm = drm->dev_private;
+
+       if (imxdrm->fbhelper)
+               drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
+#endif
+}
+
+static int imx_drm_driver_unload(struct drm_device *drm)
+{
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+       struct imx_drm_device *imxdrm = drm->dev_private;
+#endif
+
+       drm_kms_helper_poll_fini(drm);
+
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+       if (imxdrm->fbhelper)
+               drm_fbdev_cma_fini(imxdrm->fbhelper);
+#endif
+
+       component_unbind_all(drm->dev, drm);
+
+       drm_vblank_cleanup(drm);
+       drm_mode_config_cleanup(drm);
+
+       platform_set_drvdata(drm->platformdev, NULL);
+
+       return 0;
+}
+
+static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
+{
+       struct imx_drm_device *imxdrm = crtc->dev->dev_private;
+       unsigned i;
+
+       for (i = 0; i < MAX_CRTC; i++)
+               if (imxdrm->crtc[i] && imxdrm->crtc[i]->crtc == crtc)
+                       return imxdrm->crtc[i];
+
+       return NULL;
+}
+
+int imx_drm_panel_format_pins(struct drm_encoder *encoder,
+               u32 interface_pix_fmt, int hsync_pin, int vsync_pin)
+{
+       struct imx_drm_crtc_helper_funcs *helper;
+       struct imx_drm_crtc *imx_crtc;
+
+       imx_crtc = imx_drm_find_crtc(encoder->crtc);
+       if (!imx_crtc)
+               return -EINVAL;
+
+       helper = &imx_crtc->imx_drm_helper_funcs;
+       if (helper->set_interface_pix_fmt)
+               return helper->set_interface_pix_fmt(encoder->crtc,
+                               encoder->encoder_type, interface_pix_fmt,
+                               hsync_pin, vsync_pin);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins);
+
+int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt)
+{
+       return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3);
+}
+EXPORT_SYMBOL_GPL(imx_drm_panel_format);
+
+int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
+{
+       return drm_vblank_get(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
+}
+EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
+
+void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
+{
+       drm_vblank_put(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
+}
+EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
+
+void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
+{
+       drm_handle_vblank(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
+}
+EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
+
+static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
+{
+       struct imx_drm_device *imxdrm = drm->dev_private;
+       struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
+       int ret;
+
+       if (!imx_drm_crtc)
+               return -EINVAL;
+
+       if (!imx_drm_crtc->imx_drm_helper_funcs.enable_vblank)
+               return -ENOSYS;
+
+       ret = imx_drm_crtc->imx_drm_helper_funcs.enable_vblank(
+                       imx_drm_crtc->crtc);
+
+       return ret;
+}
+
+static void imx_drm_disable_vblank(struct drm_device *drm, int crtc)
+{
+       struct imx_drm_device *imxdrm = drm->dev_private;
+       struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
+
+       if (!imx_drm_crtc)
+               return;
+
+       if (!imx_drm_crtc->imx_drm_helper_funcs.disable_vblank)
+               return;
+
+       imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(imx_drm_crtc->crtc);
+}
+
+static void imx_drm_driver_preclose(struct drm_device *drm,
+               struct drm_file *file)
+{
+       int i;
+
+       if (!file->is_master)
+               return;
+
+       for (i = 0; i < MAX_CRTC; i++)
+               imx_drm_disable_vblank(drm, i);
+}
+
+static const struct file_operations imx_drm_driver_fops = {
+       .owner = THIS_MODULE,
+       .open = drm_open,
+       .release = drm_release,
+       .unlocked_ioctl = drm_ioctl,
+       .mmap = drm_gem_cma_mmap,
+       .poll = drm_poll,
+       .read = drm_read,
+       .llseek = noop_llseek,
+};
+
+void imx_drm_connector_destroy(struct drm_connector *connector)
+{
+       drm_connector_unregister(connector);
+       drm_connector_cleanup(connector);
+}
+EXPORT_SYMBOL_GPL(imx_drm_connector_destroy);
+
+void imx_drm_encoder_destroy(struct drm_encoder *encoder)
+{
+       drm_encoder_cleanup(encoder);
+}
+EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
+
+static void imx_drm_output_poll_changed(struct drm_device *drm)
+{
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+       struct imx_drm_device *imxdrm = drm->dev_private;
+
+       drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
+#endif
+}
+
+static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
+       .fb_create = drm_fb_cma_create,
+       .output_poll_changed = imx_drm_output_poll_changed,
+};
+
+/*
+ * Main DRM initialisation. This binds, initialises and registers
+ * with DRM the subcomponents of the driver.
+ */
+static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
+{
+       struct imx_drm_device *imxdrm;
+       struct drm_connector *connector;
+       int ret;
+
+       imxdrm = devm_kzalloc(drm->dev, sizeof(*imxdrm), GFP_KERNEL);
+       if (!imxdrm)
+               return -ENOMEM;
+
+       imxdrm->drm = drm;
+
+       drm->dev_private = imxdrm;
+
+       /*
+        * enable drm irq mode.
+        * - with irq_enabled = true, we can use the vblank feature.
+        *
+        * P.S. note that we wouldn't use drm irq handler but
+        *      just specific driver own one instead because
+        *      drm framework supports only one irq handler and
+        *      drivers can well take care of their interrupts
+        */
+       drm->irq_enabled = true;
+
+       /*
+        * set max width and height as default value(4096x4096).
+        * this value would be used to check framebuffer size limitation
+        * at drm_mode_addfb().
+        */
+       drm->mode_config.min_width = 64;
+       drm->mode_config.min_height = 64;
+       drm->mode_config.max_width = 4096;
+       drm->mode_config.max_height = 4096;
+       drm->mode_config.funcs = &imx_drm_mode_config_funcs;
+
+       drm_mode_config_init(drm);
+
+       ret = drm_vblank_init(drm, MAX_CRTC);
+       if (ret)
+               goto err_kms;
+
+       /*
+        * with vblank_disable_allowed = true, vblank interrupt will be
+        * disabled by drm timer once a current process gives up ownership
+        * of vblank event. (after drm_vblank_put function is called)
+        */
+       drm->vblank_disable_allowed = true;
+
+       platform_set_drvdata(drm->platformdev, drm);
+
+       /* Now try and bind all our sub-components */
+       ret = component_bind_all(drm->dev, drm);
+       if (ret)
+               goto err_vblank;
+
+       /*
+        * All components are now added, we can publish the connector sysfs
+        * entries to userspace.  This will generate hotplug events and so
+        * userspace will expect to be able to access DRM at this point.
+        */
+       list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
+               ret = drm_connector_register(connector);
+               if (ret) {
+                       dev_err(drm->dev,
+                               "[CONNECTOR:%d:%s] drm_connector_register failed: %d\n",
+                               connector->base.id,
+                               connector->name, ret);
+                       goto err_unbind;
+               }
+       }
+
+       /*
+        * All components are now initialised, so setup the fb helper.
+        * The fb helper takes copies of key hardware information, so the
+        * crtcs/connectors/encoders must not change after this point.
+        */
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+       if (legacyfb_depth != 16 && legacyfb_depth != 32) {
+               dev_warn(drm->dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
+               legacyfb_depth = 16;
+       }
+       imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
+                               drm->mode_config.num_crtc, MAX_CRTC);
+       if (IS_ERR(imxdrm->fbhelper)) {
+               ret = PTR_ERR(imxdrm->fbhelper);
+               imxdrm->fbhelper = NULL;
+               goto err_unbind;
+       }
+#endif
+
+       drm_kms_helper_poll_init(drm);
+
+       return 0;
+
+err_unbind:
+       component_unbind_all(drm->dev, drm);
+err_vblank:
+       drm_vblank_cleanup(drm);
+err_kms:
+       drm_mode_config_cleanup(drm);
+
+       return ret;
+}
+
+/*
+ * imx_drm_add_crtc - add a new crtc
+ */
+int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
+               struct imx_drm_crtc **new_crtc,
+               const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
+               struct device_node *port)
+{
+       struct imx_drm_device *imxdrm = drm->dev_private;
+       struct imx_drm_crtc *imx_drm_crtc;
+       int ret;
+
+       /*
+        * The vblank arrays are dimensioned by MAX_CRTC - we can't
+        * pass IDs greater than this to those functions.
+        */
+       if (imxdrm->pipes >= MAX_CRTC)
+               return -EINVAL;
+
+       if (imxdrm->drm->open_count)
+               return -EBUSY;
+
+       imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL);
+       if (!imx_drm_crtc)
+               return -ENOMEM;
+
+       imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
+       imx_drm_crtc->pipe = imxdrm->pipes++;
+       imx_drm_crtc->port = port;
+       imx_drm_crtc->crtc = crtc;
+
+       imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
+
+       *new_crtc = imx_drm_crtc;
+
+       ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
+       if (ret)
+               goto err_register;
+
+       drm_crtc_helper_add(crtc,
+                       imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
+
+       drm_crtc_init(drm, crtc,
+                       imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
+
+       return 0;
+
+err_register:
+       imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
+       kfree(imx_drm_crtc);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
+
+/*
+ * imx_drm_remove_crtc - remove a crtc
+ */
+int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
+{
+       struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private;
+
+       drm_crtc_cleanup(imx_drm_crtc->crtc);
+
+       imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
+
+       kfree(imx_drm_crtc);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
+
+/*
+ * Find the DRM CRTC possible mask for the connected endpoint.
+ *
+ * The encoder possible masks are defined by their position in the
+ * mode_config crtc_list.  This means that CRTCs must not be added
+ * or removed once the DRM device has been fully initialised.
+ */
+static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
+       struct device_node *endpoint)
+{
+       struct device_node *port;
+       unsigned i;
+
+       port = of_graph_get_remote_port(endpoint);
+       if (!port)
+               return 0;
+       of_node_put(port);
+
+       for (i = 0; i < MAX_CRTC; i++) {
+               struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
+
+               if (imx_drm_crtc && imx_drm_crtc->port == port)
+                       return drm_crtc_mask(imx_drm_crtc->crtc);
+       }
+
+       return 0;
+}
+
+static struct device_node *imx_drm_of_get_next_endpoint(
+               const struct device_node *parent, struct device_node *prev)
+{
+       struct device_node *node = of_graph_get_next_endpoint(parent, prev);
+
+       of_node_put(prev);
+       return node;
+}
+
+int imx_drm_encoder_parse_of(struct drm_device *drm,
+       struct drm_encoder *encoder, struct device_node *np)
+{
+       struct imx_drm_device *imxdrm = drm->dev_private;
+       struct device_node *ep = NULL;
+       uint32_t crtc_mask = 0;
+       int i;
+
+       for (i = 0; ; i++) {
+               u32 mask;
+
+               ep = imx_drm_of_get_next_endpoint(np, ep);
+               if (!ep)
+                       break;
+
+               mask = imx_drm_find_crtc_mask(imxdrm, ep);
+
+               /*
+                * If we failed to find the CRTC(s) which this encoder is
+                * supposed to be connected to, it's because the CRTC has
+                * not been registered yet.  Defer probing, and hope that
+                * the required CRTC is added later.
+                */
+               if (mask == 0)
+                       return -EPROBE_DEFER;
+
+               crtc_mask |= mask;
+       }
+
+       of_node_put(ep);
+       if (i == 0)
+               return -ENOENT;
+
+       encoder->possible_crtcs = crtc_mask;
+
+       /* FIXME: this is the mask of outputs which can clone this output. */
+       encoder->possible_clones = ~0;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
+
+/*
+ * @node: device tree node containing encoder input ports
+ * @encoder: drm_encoder
+ */
+int imx_drm_encoder_get_mux_id(struct device_node *node,
+                              struct drm_encoder *encoder)
+{
+       struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
+       struct device_node *ep = NULL;
+       struct of_endpoint endpoint;
+       struct device_node *port;
+       int ret;
+
+       if (!node || !imx_crtc)
+               return -EINVAL;
+
+       do {
+               ep = imx_drm_of_get_next_endpoint(node, ep);
+               if (!ep)
+                       break;
+
+               port = of_graph_get_remote_port(ep);
+               of_node_put(port);
+               if (port == imx_crtc->port) {
+                       ret = of_graph_parse_endpoint(ep, &endpoint);
+                       return ret ? ret : endpoint.port;
+               }
+       } while (ep);
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
+
+static const struct drm_ioctl_desc imx_drm_ioctls[] = {
+       /* none so far */
+};
+
+static struct drm_driver imx_drm_driver = {
+       .driver_features        = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
+       .load                   = imx_drm_driver_load,
+       .unload                 = imx_drm_driver_unload,
+       .lastclose              = imx_drm_driver_lastclose,
+       .preclose               = imx_drm_driver_preclose,
+       .set_busid              = drm_platform_set_busid,
+       .gem_free_object        = drm_gem_cma_free_object,
+       .gem_vm_ops             = &drm_gem_cma_vm_ops,
+       .dumb_create            = drm_gem_cma_dumb_create,
+       .dumb_map_offset        = drm_gem_cma_dumb_map_offset,
+       .dumb_destroy           = drm_gem_dumb_destroy,
+
+       .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
+       .gem_prime_import       = drm_gem_prime_import,
+       .gem_prime_export       = drm_gem_prime_export,
+       .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
+       .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+       .gem_prime_vmap         = drm_gem_cma_prime_vmap,
+       .gem_prime_vunmap       = drm_gem_cma_prime_vunmap,
+       .gem_prime_mmap         = drm_gem_cma_prime_mmap,
+       .get_vblank_counter     = drm_vblank_count,
+       .enable_vblank          = imx_drm_enable_vblank,
+       .disable_vblank         = imx_drm_disable_vblank,
+       .ioctls                 = imx_drm_ioctls,
+       .num_ioctls             = ARRAY_SIZE(imx_drm_ioctls),
+       .fops                   = &imx_drm_driver_fops,
+       .name                   = "imx-drm",
+       .desc                   = "i.MX DRM graphics",
+       .date                   = "20120507",
+       .major                  = 1,
+       .minor                  = 0,
+       .patchlevel             = 0,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+       struct device_node *np = data;
+
+       /* Special case for LDB, one device for two channels */
+       if (of_node_cmp(np->name, "lvds-channel") == 0) {
+               np = of_get_parent(np);
+               of_node_put(np);
+       }
+
+       return dev->of_node == np;
+}
+
+static int imx_drm_bind(struct device *dev)
+{
+       return drm_platform_init(&imx_drm_driver, to_platform_device(dev));
+}
+
+static void imx_drm_unbind(struct device *dev)
+{
+       drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops imx_drm_ops = {
+       .bind = imx_drm_bind,
+       .unbind = imx_drm_unbind,
+};
+
+static int imx_drm_platform_probe(struct platform_device *pdev)
+{
+       struct device_node *ep, *port, *remote;
+       struct component_match *match = NULL;
+       int ret;
+       int i;
+
+       /*
+        * Bind the IPU display interface ports first, so that
+        * imx_drm_encoder_parse_of called from encoder .bind callbacks
+        * works as expected.
+        */
+       for (i = 0; ; i++) {
+               port = of_parse_phandle(pdev->dev.of_node, "ports", i);
+               if (!port)
+                       break;
+
+               component_match_add(&pdev->dev, &match, compare_of, port);
+       }
+
+       if (i == 0) {
+               dev_err(&pdev->dev, "missing 'ports' property\n");
+               return -ENODEV;
+       }
+
+       /* Then bind all encoders */
+       for (i = 0; ; i++) {
+               port = of_parse_phandle(pdev->dev.of_node, "ports", i);
+               if (!port)
+                       break;
+
+               for_each_child_of_node(port, ep) {
+                       remote = of_graph_get_remote_port_parent(ep);
+                       if (!remote || !of_device_is_available(remote)) {
+                               of_node_put(remote);
+                               continue;
+                       } else if (!of_device_is_available(remote->parent)) {
+                               dev_warn(&pdev->dev, "parent device of %s is not available\n",
+                                        remote->full_name);
+                               of_node_put(remote);
+                               continue;
+                       }
+
+                       component_match_add(&pdev->dev, &match, compare_of, remote);
+                       of_node_put(remote);
+               }
+               of_node_put(port);
+       }
+
+       ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
+
+       return component_master_add_with_match(&pdev->dev, &imx_drm_ops, match);
+}
+
+static int imx_drm_platform_remove(struct platform_device *pdev)
+{
+       component_master_del(&pdev->dev, &imx_drm_ops);
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int imx_drm_suspend(struct device *dev)
+{
+       struct drm_device *drm_dev = dev_get_drvdata(dev);
+
+       /* The drm_dev is NULL before .load hook is called */
+       if (drm_dev == NULL)
+               return 0;
+
+       drm_kms_helper_poll_disable(drm_dev);
+
+       return 0;
+}
+
+static int imx_drm_resume(struct device *dev)
+{
+       struct drm_device *drm_dev = dev_get_drvdata(dev);
+
+       if (drm_dev == NULL)
+               return 0;
+
+       drm_helper_resume_force_mode(drm_dev);
+       drm_kms_helper_poll_enable(drm_dev);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(imx_drm_pm_ops, imx_drm_suspend, imx_drm_resume);
+
+static const struct of_device_id imx_drm_dt_ids[] = {
+       { .compatible = "fsl,imx-display-subsystem", },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx_drm_dt_ids);
+
+static struct platform_driver imx_drm_pdrv = {
+       .probe          = imx_drm_platform_probe,
+       .remove         = imx_drm_platform_remove,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "imx-drm",
+               .pm     = &imx_drm_pm_ops,
+               .of_match_table = imx_drm_dt_ids,
+       },
+};
+module_platform_driver(imx_drm_pdrv);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("i.MX drm driver core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h
new file mode 100644 (file)
index 0000000..7453ae0
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef _IMX_DRM_H_
+#define _IMX_DRM_H_
+
+struct device_node;
+struct drm_crtc;
+struct drm_connector;
+struct drm_device;
+struct drm_display_mode;
+struct drm_encoder;
+struct drm_fbdev_cma;
+struct drm_framebuffer;
+struct imx_drm_crtc;
+struct platform_device;
+
+int imx_drm_crtc_id(struct imx_drm_crtc *crtc);
+
+struct imx_drm_crtc_helper_funcs {
+       int (*enable_vblank)(struct drm_crtc *crtc);
+       void (*disable_vblank)(struct drm_crtc *crtc);
+       int (*set_interface_pix_fmt)(struct drm_crtc *crtc, u32 encoder_type,
+                       u32 pix_fmt, int hsync_pin, int vsync_pin);
+       const struct drm_crtc_helper_funcs *crtc_helper_funcs;
+       const struct drm_crtc_funcs *crtc_funcs;
+};
+
+int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
+               struct imx_drm_crtc **new_crtc,
+               const struct imx_drm_crtc_helper_funcs *imx_helper_funcs,
+               struct device_node *port);
+int imx_drm_remove_crtc(struct imx_drm_crtc *);
+int imx_drm_init_drm(struct platform_device *pdev,
+               int preferred_bpp);
+int imx_drm_exit_drm(void);
+
+int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc);
+void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc);
+void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc);
+
+void imx_drm_mode_config_init(struct drm_device *drm);
+
+struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
+
+int imx_drm_panel_format_pins(struct drm_encoder *encoder,
+               u32 interface_pix_fmt, int hsync_pin, int vsync_pin);
+int imx_drm_panel_format(struct drm_encoder *encoder,
+               u32 interface_pix_fmt);
+
+int imx_drm_encoder_get_mux_id(struct device_node *node,
+               struct drm_encoder *encoder);
+int imx_drm_encoder_parse_of(struct drm_device *drm,
+       struct drm_encoder *encoder, struct device_node *np);
+
+void imx_drm_connector_destroy(struct drm_connector *connector);
+void imx_drm_encoder_destroy(struct drm_encoder *encoder);
+
+#endif /* _IMX_DRM_H_ */
diff --git a/drivers/gpu/drm/imx/imx-hdmi.c b/drivers/gpu/drm/imx/imx-hdmi.c
new file mode 100644 (file)
index 0000000..aaec6b2
--- /dev/null
@@ -0,0 +1,1767 @@
+/*
+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ * SH-Mobile High-Definition Multimedia Interface (HDMI) driver
+ * for SLISHDMI13T and SLIPHDMIT IP cores
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ */
+
+#include <linux/component.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/hdmi.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/of_device.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+#include <video/imx-ipu-v3.h>
+
+#include "imx-hdmi.h"
+#include "imx-drm.h"
+
+#define HDMI_EDID_LEN          512
+
+#define RGB                    0
+#define YCBCR444               1
+#define YCBCR422_16BITS                2
+#define YCBCR422_8BITS         3
+#define XVYCC444               4
+
+enum hdmi_datamap {
+       RGB444_8B = 0x01,
+       RGB444_10B = 0x03,
+       RGB444_12B = 0x05,
+       RGB444_16B = 0x07,
+       YCbCr444_8B = 0x09,
+       YCbCr444_10B = 0x0B,
+       YCbCr444_12B = 0x0D,
+       YCbCr444_16B = 0x0F,
+       YCbCr422_8B = 0x16,
+       YCbCr422_10B = 0x14,
+       YCbCr422_12B = 0x12,
+};
+
+enum imx_hdmi_devtype {
+       IMX6Q_HDMI,
+       IMX6DL_HDMI,
+};
+
+static const u16 csc_coeff_default[3][4] = {
+       { 0x2000, 0x0000, 0x0000, 0x0000 },
+       { 0x0000, 0x2000, 0x0000, 0x0000 },
+       { 0x0000, 0x0000, 0x2000, 0x0000 }
+};
+
+static const u16 csc_coeff_rgb_out_eitu601[3][4] = {
+       { 0x2000, 0x6926, 0x74fd, 0x010e },
+       { 0x2000, 0x2cdd, 0x0000, 0x7e9a },
+       { 0x2000, 0x0000, 0x38b4, 0x7e3b }
+};
+
+static const u16 csc_coeff_rgb_out_eitu709[3][4] = {
+       { 0x2000, 0x7106, 0x7a02, 0x00a7 },
+       { 0x2000, 0x3264, 0x0000, 0x7e6d },
+       { 0x2000, 0x0000, 0x3b61, 0x7e25 }
+};
+
+static const u16 csc_coeff_rgb_in_eitu601[3][4] = {
+       { 0x2591, 0x1322, 0x074b, 0x0000 },
+       { 0x6535, 0x2000, 0x7acc, 0x0200 },
+       { 0x6acd, 0x7534, 0x2000, 0x0200 }
+};
+
+static const u16 csc_coeff_rgb_in_eitu709[3][4] = {
+       { 0x2dc5, 0x0d9b, 0x049e, 0x0000 },
+       { 0x62f0, 0x2000, 0x7d11, 0x0200 },
+       { 0x6756, 0x78ab, 0x2000, 0x0200 }
+};
+
+struct hdmi_vmode {
+       bool mdvi;
+       bool mhsyncpolarity;
+       bool mvsyncpolarity;
+       bool minterlaced;
+       bool mdataenablepolarity;
+
+       unsigned int mpixelclock;
+       unsigned int mpixelrepetitioninput;
+       unsigned int mpixelrepetitionoutput;
+};
+
+struct hdmi_data_info {
+       unsigned int enc_in_format;
+       unsigned int enc_out_format;
+       unsigned int enc_color_depth;
+       unsigned int colorimetry;
+       unsigned int pix_repet_factor;
+       unsigned int hdcp_enable;
+       struct hdmi_vmode video_mode;
+};
+
+struct imx_hdmi {
+       struct drm_connector connector;
+       struct drm_encoder encoder;
+
+       enum imx_hdmi_devtype dev_type;
+       struct device *dev;
+       struct clk *isfr_clk;
+       struct clk *iahb_clk;
+
+       struct hdmi_data_info hdmi_data;
+       int vic;
+
+       u8 edid[HDMI_EDID_LEN];
+       bool cable_plugin;
+
+       bool phy_enabled;
+       struct drm_display_mode previous_mode;
+
+       struct regmap *regmap;
+       struct i2c_adapter *ddc;
+       void __iomem *regs;
+
+       unsigned int sample_rate;
+       int ratio;
+};
+
+static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di)
+{
+       regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
+                          IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
+                          ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
+}
+
+static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
+{
+       writeb(val, hdmi->regs + offset);
+}
+
+static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
+{
+       return readb(hdmi->regs + offset);
+}
+
+static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
+{
+       u8 val = hdmi_readb(hdmi, reg) & ~mask;
+
+       val |= data & mask;
+       hdmi_writeb(hdmi, val, reg);
+}
+
+static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
+                     u8 shift, u8 mask)
+{
+       hdmi_modb(hdmi, data << shift, mask, reg);
+}
+
+static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
+                                        unsigned int value)
+{
+       hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
+       hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2);
+       hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);
+
+       /* nshift factor = 0 */
+       hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
+}
+
+static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
+{
+       /* Must be set/cleared first */
+       hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
+
+       hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
+       hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
+       hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
+                   HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
+}
+
+static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk,
+                                  unsigned int ratio)
+{
+       unsigned int n = (128 * freq) / 1000;
+
+       switch (freq) {
+       case 32000:
+               if (pixel_clk == 25170000)
+                       n = (ratio == 150) ? 9152 : 4576;
+               else if (pixel_clk == 27020000)
+                       n = (ratio == 150) ? 8192 : 4096;
+               else if (pixel_clk == 74170000 || pixel_clk == 148350000)
+                       n = 11648;
+               else
+                       n = 4096;
+               break;
+
+       case 44100:
+               if (pixel_clk == 25170000)
+                       n = 7007;
+               else if (pixel_clk == 74170000)
+                       n = 17836;
+               else if (pixel_clk == 148350000)
+                       n = (ratio == 150) ? 17836 : 8918;
+               else
+                       n = 6272;
+               break;
+
+       case 48000:
+               if (pixel_clk == 25170000)
+                       n = (ratio == 150) ? 9152 : 6864;
+               else if (pixel_clk == 27020000)
+                       n = (ratio == 150) ? 8192 : 6144;
+               else if (pixel_clk == 74170000)
+                       n = 11648;
+               else if (pixel_clk == 148350000)
+                       n = (ratio == 150) ? 11648 : 5824;
+               else
+                       n = 6144;
+               break;
+
+       case 88200:
+               n = hdmi_compute_n(44100, pixel_clk, ratio) * 2;
+               break;
+
+       case 96000:
+               n = hdmi_compute_n(48000, pixel_clk, ratio) * 2;
+               break;
+
+       case 176400:
+               n = hdmi_compute_n(44100, pixel_clk, ratio) * 4;
+               break;
+
+       case 192000:
+               n = hdmi_compute_n(48000, pixel_clk, ratio) * 4;
+               break;
+
+       default:
+               break;
+       }
+
+       return n;
+}
+
+static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
+                                    unsigned int ratio)
+{
+       unsigned int cts = 0;
+
+       pr_debug("%s: freq: %d pixel_clk: %ld ratio: %d\n", __func__, freq,
+                pixel_clk, ratio);
+
+       switch (freq) {
+       case 32000:
+               if (pixel_clk == 297000000) {
+                       cts = 222750;
+                       break;
+               }
+       case 48000:
+       case 96000:
+       case 192000:
+               switch (pixel_clk) {
+               case 25200000:
+               case 27000000:
+               case 54000000:
+               case 74250000:
+               case 148500000:
+                       cts = pixel_clk / 1000;
+                       break;
+               case 297000000:
+                       cts = 247500;
+                       break;
+               /*
+                * All other TMDS clocks are not supported by
+                * DWC_hdmi_tx. The TMDS clocks divided or
+                * multiplied by 1,001 coefficients are not
+                * supported.
+                */
+               default:
+                       break;
+               }
+               break;
+       case 44100:
+       case 88200:
+       case 176400:
+               switch (pixel_clk) {
+               case 25200000:
+                       cts = 28000;
+                       break;
+               case 27000000:
+                       cts = 30000;
+                       break;
+               case 54000000:
+                       cts = 60000;
+                       break;
+               case 74250000:
+                       cts = 82500;
+                       break;
+               case 148500000:
+                       cts = 165000;
+                       break;
+               case 297000000:
+                       cts = 247500;
+                       break;
+               default:
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+       if (ratio == 100)
+               return cts;
+       return (cts * ratio) / 100;
+}
+
+static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
+       unsigned long pixel_clk)
+{
+       unsigned int clk_n, clk_cts;
+
+       clk_n = hdmi_compute_n(hdmi->sample_rate, pixel_clk,
+                              hdmi->ratio);
+       clk_cts = hdmi_compute_cts(hdmi->sample_rate, pixel_clk,
+                                  hdmi->ratio);
+
+       if (!clk_cts) {
+               dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
+                        __func__, pixel_clk);
+               return;
+       }
+
+       dev_dbg(hdmi->dev, "%s: samplerate=%d  ratio=%d  pixelclk=%lu  N=%d cts=%d\n",
+               __func__, hdmi->sample_rate, hdmi->ratio,
+               pixel_clk, clk_n, clk_cts);
+
+       hdmi_set_clock_regenerator_n(hdmi, clk_n);
+       hdmi_regenerate_cts(hdmi, clk_cts);
+}
+
+static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi)
+{
+       hdmi_set_clk_regenerator(hdmi, 74250000);
+}
+
+static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
+{
+       hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
+}
+
+/*
+ * this submodule is responsible for the video data synchronization.
+ * for example, for RGB 4:4:4 input, the data map is defined as
+ *                     pin{47~40} <==> R[7:0]
+ *                     pin{31~24} <==> G[7:0]
+ *                     pin{15~8}  <==> B[7:0]
+ */
+static void hdmi_video_sample(struct imx_hdmi *hdmi)
+{
+       int color_format = 0;
+       u8 val;
+
+       if (hdmi->hdmi_data.enc_in_format == RGB) {
+               if (hdmi->hdmi_data.enc_color_depth == 8)
+                       color_format = 0x01;
+               else if (hdmi->hdmi_data.enc_color_depth == 10)
+                       color_format = 0x03;
+               else if (hdmi->hdmi_data.enc_color_depth == 12)
+                       color_format = 0x05;
+               else if (hdmi->hdmi_data.enc_color_depth == 16)
+                       color_format = 0x07;
+               else
+                       return;
+       } else if (hdmi->hdmi_data.enc_in_format == YCBCR444) {
+               if (hdmi->hdmi_data.enc_color_depth == 8)
+                       color_format = 0x09;
+               else if (hdmi->hdmi_data.enc_color_depth == 10)
+                       color_format = 0x0B;
+               else if (hdmi->hdmi_data.enc_color_depth == 12)
+                       color_format = 0x0D;
+               else if (hdmi->hdmi_data.enc_color_depth == 16)
+                       color_format = 0x0F;
+               else
+                       return;
+       } else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) {
+               if (hdmi->hdmi_data.enc_color_depth == 8)
+                       color_format = 0x16;
+               else if (hdmi->hdmi_data.enc_color_depth == 10)
+                       color_format = 0x14;
+               else if (hdmi->hdmi_data.enc_color_depth == 12)
+                       color_format = 0x12;
+               else
+                       return;
+       }
+
+       val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
+               ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
+               HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
+       hdmi_writeb(hdmi, val, HDMI_TX_INVID0);
+
+       /* Enable TX stuffing: When DE is inactive, fix the output data to 0 */
+       val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
+               HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
+               HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
+       hdmi_writeb(hdmi, val, HDMI_TX_INSTUFFING);
+       hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA0);
+       hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA1);
+       hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA0);
+       hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA1);
+       hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA0);
+       hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1);
+}
+
+static int is_color_space_conversion(struct imx_hdmi *hdmi)
+{
+       return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format;
+}
+
+static int is_color_space_decimation(struct imx_hdmi *hdmi)
+{
+       if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
+               return 0;
+       if (hdmi->hdmi_data.enc_in_format == RGB ||
+           hdmi->hdmi_data.enc_in_format == YCBCR444)
+               return 1;
+       return 0;
+}
+
+static int is_color_space_interpolation(struct imx_hdmi *hdmi)
+{
+       if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
+               return 0;
+       if (hdmi->hdmi_data.enc_out_format == RGB ||
+           hdmi->hdmi_data.enc_out_format == YCBCR444)
+               return 1;
+       return 0;
+}
+
+static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
+{
+       const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
+       unsigned i;
+       u32 csc_scale = 1;
+
+       if (is_color_space_conversion(hdmi)) {
+               if (hdmi->hdmi_data.enc_out_format == RGB) {
+                       if (hdmi->hdmi_data.colorimetry ==
+                                       HDMI_COLORIMETRY_ITU_601)
+                               csc_coeff = &csc_coeff_rgb_out_eitu601;
+                       else
+                               csc_coeff = &csc_coeff_rgb_out_eitu709;
+               } else if (hdmi->hdmi_data.enc_in_format == RGB) {
+                       if (hdmi->hdmi_data.colorimetry ==
+                                       HDMI_COLORIMETRY_ITU_601)
+                               csc_coeff = &csc_coeff_rgb_in_eitu601;
+                       else
+                               csc_coeff = &csc_coeff_rgb_in_eitu709;
+                       csc_scale = 0;
+               }
+       }
+
+       /* The CSC registers are sequential, alternating MSB then LSB */
+       for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) {
+               u16 coeff_a = (*csc_coeff)[0][i];
+               u16 coeff_b = (*csc_coeff)[1][i];
+               u16 coeff_c = (*csc_coeff)[2][i];
+
+               hdmi_writeb(hdmi, coeff_a & 0xff,
+                       HDMI_CSC_COEF_A1_LSB + i * 2);
+               hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
+               hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
+               hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
+               hdmi_writeb(hdmi, coeff_c & 0xff,
+                       HDMI_CSC_COEF_C1_LSB + i * 2);
+               hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
+       }
+
+       hdmi_modb(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK,
+                 HDMI_CSC_SCALE);
+}
+
+static void hdmi_video_csc(struct imx_hdmi *hdmi)
+{
+       int color_depth = 0;
+       int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
+       int decimation = 0;
+
+       /* YCC422 interpolation to 444 mode */
+       if (is_color_space_interpolation(hdmi))
+               interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1;
+       else if (is_color_space_decimation(hdmi))
+               decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3;
+
+       if (hdmi->hdmi_data.enc_color_depth == 8)
+               color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP;
+       else if (hdmi->hdmi_data.enc_color_depth == 10)
+               color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP;
+       else if (hdmi->hdmi_data.enc_color_depth == 12)
+               color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP;
+       else if (hdmi->hdmi_data.enc_color_depth == 16)
+               color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP;
+       else
+               return;
+
+       /* Configure the CSC registers */
+       hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG);
+       hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
+                 HDMI_CSC_SCALE);
+
+       imx_hdmi_update_csc_coeffs(hdmi);
+}
+
+/*
+ * HDMI video packetizer is used to packetize the data.
+ * for example, if input is YCC422 mode or repeater is used,
+ * data should be repacked this module can be bypassed.
+ */
+static void hdmi_video_packetize(struct imx_hdmi *hdmi)
+{
+       unsigned int color_depth = 0;
+       unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
+       unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
+       struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
+       u8 val, vp_conf;
+
+       if (hdmi_data->enc_out_format == RGB
+               || hdmi_data->enc_out_format == YCBCR444) {
+               if (!hdmi_data->enc_color_depth)
+                       output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
+               else if (hdmi_data->enc_color_depth == 8) {
+                       color_depth = 4;
+                       output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
+               } else if (hdmi_data->enc_color_depth == 10)
+                       color_depth = 5;
+               else if (hdmi_data->enc_color_depth == 12)
+                       color_depth = 6;
+               else if (hdmi_data->enc_color_depth == 16)
+                       color_depth = 7;
+               else
+                       return;
+       } else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
+               if (!hdmi_data->enc_color_depth ||
+                   hdmi_data->enc_color_depth == 8)
+                       remap_size = HDMI_VP_REMAP_YCC422_16bit;
+               else if (hdmi_data->enc_color_depth == 10)
+                       remap_size = HDMI_VP_REMAP_YCC422_20bit;
+               else if (hdmi_data->enc_color_depth == 12)
+                       remap_size = HDMI_VP_REMAP_YCC422_24bit;
+               else
+                       return;
+               output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
+       } else
+               return;
+
+       /* set the packetizer registers */
+       val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
+               HDMI_VP_PR_CD_COLOR_DEPTH_MASK) |
+               ((hdmi_data->pix_repet_factor <<
+               HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) &
+               HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
+       hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
+
+       hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
+                 HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);
+
+       /* Data from pixel repeater block */
+       if (hdmi_data->pix_repet_factor > 1) {
+               vp_conf = HDMI_VP_CONF_PR_EN_ENABLE |
+                         HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
+       } else { /* data from packetizer block */
+               vp_conf = HDMI_VP_CONF_PR_EN_DISABLE |
+                         HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
+       }
+
+       hdmi_modb(hdmi, vp_conf,
+                 HDMI_VP_CONF_PR_EN_MASK |
+                 HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
+
+       hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
+                 HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);
+
+       hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
+
+       if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
+               vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
+                         HDMI_VP_CONF_PP_EN_ENABLE |
+                         HDMI_VP_CONF_YCC422_EN_DISABLE;
+       } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
+               vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
+                         HDMI_VP_CONF_PP_EN_DISABLE |
+                         HDMI_VP_CONF_YCC422_EN_ENABLE;
+       } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
+               vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE |
+                         HDMI_VP_CONF_PP_EN_DISABLE |
+                         HDMI_VP_CONF_YCC422_EN_DISABLE;
+       } else {
+               return;
+       }
+
+       hdmi_modb(hdmi, vp_conf,
+                 HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK |
+                 HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
+
+       hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
+                       HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE,
+                 HDMI_VP_STUFF_PP_STUFFING_MASK |
+                 HDMI_VP_STUFF_YCC422_STUFFING_MASK, HDMI_VP_STUFF);
+
+       hdmi_modb(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
+                 HDMI_VP_CONF);
+}
+
+static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
+                                               unsigned char bit)
+{
+       hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
+                 HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
+                                               unsigned char bit)
+{
+       hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
+                 HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
+                                               unsigned char bit)
+{
+       hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
+                 HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
+                                               unsigned char bit)
+{
+       hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
+}
+
+static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
+                                               unsigned char bit)
+{
+       hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
+}
+
+static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
+{
+       while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
+               if (msec-- == 0)
+                       return false;
+               udelay(1000);
+       }
+       return true;
+}
+
+static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
+                             unsigned char addr)
+{
+       hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
+       hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
+       hdmi_writeb(hdmi, (unsigned char)(data >> 8),
+               HDMI_PHY_I2CM_DATAO_1_ADDR);
+       hdmi_writeb(hdmi, (unsigned char)(data >> 0),
+               HDMI_PHY_I2CM_DATAO_0_ADDR);
+       hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
+               HDMI_PHY_I2CM_OPERATION_ADDR);
+       hdmi_phy_wait_i2c_done(hdmi, 1000);
+}
+
+static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
+                                    unsigned char addr)
+{
+       __hdmi_phy_i2c_write(hdmi, data, addr);
+       return 0;
+}
+
+static void imx_hdmi_phy_enable_power(struct imx_hdmi *hdmi, u8 enable)
+{
+       hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+                        HDMI_PHY_CONF0_PDZ_OFFSET,
+                        HDMI_PHY_CONF0_PDZ_MASK);
+}
+
+static void imx_hdmi_phy_enable_tmds(struct imx_hdmi *hdmi, u8 enable)
+{
+       hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+                        HDMI_PHY_CONF0_ENTMDS_OFFSET,
+                        HDMI_PHY_CONF0_ENTMDS_MASK);
+}
+
+static void imx_hdmi_phy_gen2_pddq(struct imx_hdmi *hdmi, u8 enable)
+{
+       hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+                        HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
+                        HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
+}
+
+static void imx_hdmi_phy_gen2_txpwron(struct imx_hdmi *hdmi, u8 enable)
+{
+       hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+                        HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
+                        HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
+}
+
+static void imx_hdmi_phy_sel_data_en_pol(struct imx_hdmi *hdmi, u8 enable)
+{
+       hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+                        HDMI_PHY_CONF0_SELDATAENPOL_OFFSET,
+                        HDMI_PHY_CONF0_SELDATAENPOL_MASK);
+}
+
+static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
+{
+       hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+                        HDMI_PHY_CONF0_SELDIPIF_OFFSET,
+                        HDMI_PHY_CONF0_SELDIPIF_MASK);
+}
+
+enum {
+       RES_8,
+       RES_10,
+       RES_12,
+       RES_MAX,
+};
+
+struct mpll_config {
+       unsigned long mpixelclock;
+       struct {
+               u16 cpce;
+               u16 gmp;
+       } res[RES_MAX];
+};
+
+static const struct mpll_config mpll_config[] = {
+       {
+               45250000, {
+                       { 0x01e0, 0x0000 },
+                       { 0x21e1, 0x0000 },
+                       { 0x41e2, 0x0000 }
+               },
+       }, {
+               92500000, {
+                       { 0x0140, 0x0005 },
+                       { 0x2141, 0x0005 },
+                       { 0x4142, 0x0005 },
+               },
+       }, {
+               148500000, {
+                       { 0x00a0, 0x000a },
+                       { 0x20a1, 0x000a },
+                       { 0x40a2, 0x000a },
+               },
+       }, {
+               ~0UL, {
+                       { 0x00a0, 0x000a },
+                       { 0x2001, 0x000f },
+                       { 0x4002, 0x000f },
+               },
+       }
+};
+
+struct curr_ctrl {
+       unsigned long mpixelclock;
+       u16 curr[RES_MAX];
+};
+
+static const struct curr_ctrl curr_ctrl[] = {
+       /*      pixelclk     bpp8    bpp10   bpp12 */
+       {
+                54000000, { 0x091c, 0x091c, 0x06dc },
+       }, {
+                58400000, { 0x091c, 0x06dc, 0x06dc },
+       }, {
+                72000000, { 0x06dc, 0x06dc, 0x091c },
+       }, {
+                74250000, { 0x06dc, 0x0b5c, 0x091c },
+       }, {
+               118800000, { 0x091c, 0x091c, 0x06dc },
+       }, {
+               216000000, { 0x06dc, 0x0b5c, 0x091c },
+       }
+};
+
+static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
+                             unsigned char res, int cscon)
+{
+       unsigned res_idx, i;
+       u8 val, msec;
+
+       if (prep)
+               return -EINVAL;
+
+       switch (res) {
+       case 0: /* color resolution 0 is 8 bit colour depth */
+       case 8:
+               res_idx = RES_8;
+               break;
+       case 10:
+               res_idx = RES_10;
+               break;
+       case 12:
+               res_idx = RES_12;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Enable csc path */
+       if (cscon)
+               val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH;
+       else
+               val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS;
+
+       hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL);
+
+       /* gen2 tx power off */
+       imx_hdmi_phy_gen2_txpwron(hdmi, 0);
+
+       /* gen2 pddq */
+       imx_hdmi_phy_gen2_pddq(hdmi, 1);
+
+       /* PHY reset */
+       hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
+       hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
+
+       hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
+
+       hdmi_phy_test_clear(hdmi, 1);
+       hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
+                       HDMI_PHY_I2CM_SLAVE_ADDR);
+       hdmi_phy_test_clear(hdmi, 0);
+
+       /* PLL/MPLL Cfg - always match on final entry */
+       for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++)
+               if (hdmi->hdmi_data.video_mode.mpixelclock <=
+                   mpll_config[i].mpixelclock)
+                       break;
+
+       hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06);
+       hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15);
+
+       for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++)
+               if (hdmi->hdmi_data.video_mode.mpixelclock <=
+                   curr_ctrl[i].mpixelclock)
+                       break;
+
+       if (i >= ARRAY_SIZE(curr_ctrl)) {
+               dev_err(hdmi->dev,
+                               "Pixel clock %d - unsupported by HDMI\n",
+                               hdmi->hdmi_data.video_mode.mpixelclock);
+               return -EINVAL;
+       }
+
+       /* CURRCTRL */
+       hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10);
+
+       hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);  /* PLLPHBYCTRL */
+       hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+       /* RESISTANCE TERM 133Ohm Cfg */
+       hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);  /* TXTERM */
+       /* PREEMP Cgf 0.00 */
+       hdmi_phy_i2c_write(hdmi, 0x800d, 0x09);  /* CKSYMTXCTRL */
+       /* TX/CK LVL 10 */
+       hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E);  /* VLEVCTRL */
+       /* REMOVE CLK TERM */
+       hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);  /* CKCALCTRL */
+
+       imx_hdmi_phy_enable_power(hdmi, 1);
+
+       /* toggle TMDS enable */
+       imx_hdmi_phy_enable_tmds(hdmi, 0);
+       imx_hdmi_phy_enable_tmds(hdmi, 1);
+
+       /* gen2 tx power on */
+       imx_hdmi_phy_gen2_txpwron(hdmi, 1);
+       imx_hdmi_phy_gen2_pddq(hdmi, 0);
+
+       /*Wait for PHY PLL lock */
+       msec = 5;
+       do {
+               val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
+               if (!val)
+                       break;
+
+               if (msec == 0) {
+                       dev_err(hdmi->dev, "PHY PLL not locked\n");
+                       return -ETIMEDOUT;
+               }
+
+               udelay(1000);
+               msec--;
+       } while (1);
+
+       return 0;
+}
+
+static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
+{
+       int i, ret;
+       bool cscon = false;
+
+       /*check csc whether needed activated in HDMI mode */
+       cscon = (is_color_space_conversion(hdmi) &&
+                       !hdmi->hdmi_data.video_mode.mdvi);
+
+       /* HDMI Phy spec says to do the phy initialization sequence twice */
+       for (i = 0; i < 2; i++) {
+               imx_hdmi_phy_sel_data_en_pol(hdmi, 1);
+               imx_hdmi_phy_sel_interface_control(hdmi, 0);
+               imx_hdmi_phy_enable_tmds(hdmi, 0);
+               imx_hdmi_phy_enable_power(hdmi, 0);
+
+               /* Enable CSC */
+               ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
+               if (ret)
+                       return ret;
+       }
+
+       hdmi->phy_enabled = true;
+       return 0;
+}
+
+static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
+{
+       u8 de;
+
+       if (hdmi->hdmi_data.video_mode.mdataenablepolarity)
+               de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
+       else
+               de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
+
+       /* disable rx detect */
+       hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE,
+                 HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0);
+
+       hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG);
+
+       hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE,
+                 HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
+}
+
+static void hdmi_config_AVI(struct imx_hdmi *hdmi)
+{
+       u8 val, pix_fmt, under_scan;
+       u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry;
+       bool aspect_16_9;
+
+       aspect_16_9 = false; /* FIXME */
+
+       /* AVI Data Byte 1 */
+       if (hdmi->hdmi_data.enc_out_format == YCBCR444)
+               pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR444;
+       else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS)
+               pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR422;
+       else
+               pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_RGB;
+
+               under_scan =  HDMI_FC_AVICONF0_SCAN_INFO_NODATA;
+
+       /*
+        * Active format identification data is present in the AVI InfoFrame.
+        * Under scan info, no bar data
+        */
+       val = pix_fmt | under_scan |
+               HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT |
+               HDMI_FC_AVICONF0_BAR_DATA_NO_DATA;
+
+       hdmi_writeb(hdmi, val, HDMI_FC_AVICONF0);
+
+       /* AVI Data Byte 2 -Set the Aspect Ratio */
+       if (aspect_16_9) {
+               act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9;
+               coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9;
+       } else {
+               act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3;
+               coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3;
+       }
+
+       /* Set up colorimetry */
+       if (hdmi->hdmi_data.enc_out_format == XVYCC444) {
+               colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO;
+               if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
+                       ext_colorimetry =
+                               HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+               else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
+                       ext_colorimetry =
+                               HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709;
+       } else if (hdmi->hdmi_data.enc_out_format != RGB) {
+               if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
+                       colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_SMPTE;
+               else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
+                       colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_ITUR;
+               ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+       } else { /* Carries no data */
+               colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA;
+               ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+       }
+
+       val = colorimetry | coded_ratio | act_ratio;
+       hdmi_writeb(hdmi, val, HDMI_FC_AVICONF1);
+
+       /* AVI Data Byte 3 */
+       val = HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA | ext_colorimetry |
+               HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT |
+               HDMI_FC_AVICONF2_SCALING_NONE;
+       hdmi_writeb(hdmi, val, HDMI_FC_AVICONF2);
+
+       /* AVI Data Byte 4 */
+       hdmi_writeb(hdmi, hdmi->vic, HDMI_FC_AVIVID);
+
+       /* AVI Data Byte 5- set up input and output pixel repetition */
+       val = (((hdmi->hdmi_data.video_mode.mpixelrepetitioninput + 1) <<
+               HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET) &
+               HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK) |
+               ((hdmi->hdmi_data.video_mode.mpixelrepetitionoutput <<
+               HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET) &
+               HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK);
+       hdmi_writeb(hdmi, val, HDMI_FC_PRCONF);
+
+       /* IT Content and quantization range = don't care */
+       val = HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS |
+               HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED;
+       hdmi_writeb(hdmi, val, HDMI_FC_AVICONF3);
+
+       /* AVI Data Bytes 6-13 */
+       hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB0);
+       hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB1);
+       hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB0);
+       hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB1);
+       hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB0);
+       hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB1);
+       hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB0);
+       hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1);
+}
+
+static void hdmi_av_composer(struct imx_hdmi *hdmi,
+                            const struct drm_display_mode *mode)
+{
+       u8 inv_val;
+       struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
+       int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
+
+       vmode->mhsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
+       vmode->mvsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
+       vmode->minterlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
+       vmode->mpixelclock = mode->clock * 1000;
+
+       dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
+
+       /* Set up HDMI_FC_INVIDCONF */
+       inv_val = (hdmi->hdmi_data.hdcp_enable ?
+               HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
+               HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
+
+       inv_val |= (vmode->mvsyncpolarity ?
+               HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
+               HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
+
+       inv_val |= (vmode->mhsyncpolarity ?
+               HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
+               HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW);
+
+       inv_val |= (vmode->mdataenablepolarity ?
+               HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
+               HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW);
+
+       if (hdmi->vic == 39)
+               inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH;
+       else
+               inv_val |= (vmode->minterlaced ?
+                       HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH :
+                       HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW);
+
+       inv_val |= (vmode->minterlaced ?
+               HDMI_FC_INVIDCONF_IN_I_P_INTERLACED :
+               HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE);
+
+       inv_val |= (vmode->mdvi ?
+               HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE :
+               HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE);
+
+       hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF);
+
+       /* Set up horizontal active pixel width */
+       hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
+       hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
+
+       /* Set up vertical active lines */
+       hdmi_writeb(hdmi, mode->vdisplay >> 8, HDMI_FC_INVACTV1);
+       hdmi_writeb(hdmi, mode->vdisplay, HDMI_FC_INVACTV0);
+
+       /* Set up horizontal blanking pixel region width */
+       hblank = mode->htotal - mode->hdisplay;
+       hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1);
+       hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0);
+
+       /* Set up vertical blanking pixel region width */
+       vblank = mode->vtotal - mode->vdisplay;
+       hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK);
+
+       /* Set up HSYNC active edge delay width (in pixel clks) */
+       h_de_hs = mode->hsync_start - mode->hdisplay;
+       hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1);
+       hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0);
+
+       /* Set up VSYNC active edge delay (in lines) */
+       v_de_vs = mode->vsync_start - mode->vdisplay;
+       hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY);
+
+       /* Set up HSYNC active pulse width (in pixel clks) */
+       hsync_len = mode->hsync_end - mode->hsync_start;
+       hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
+       hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
+
+       /* Set up VSYNC active edge delay (in lines) */
+       vsync_len = mode->vsync_end - mode->vsync_start;
+       hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
+}
+
+static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
+{
+       if (!hdmi->phy_enabled)
+               return;
+
+       imx_hdmi_phy_enable_tmds(hdmi, 0);
+       imx_hdmi_phy_enable_power(hdmi, 0);
+
+       hdmi->phy_enabled = false;
+}
+
+/* HDMI Initialization Step B.4 */
+static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
+{
+       u8 clkdis;
+
+       /* control period minimum duration */
+       hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR);
+       hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR);
+       hdmi_writeb(hdmi, 1, HDMI_FC_EXCTRLSPAC);
+
+       /* Set to fill TMDS data channels */
+       hdmi_writeb(hdmi, 0x0B, HDMI_FC_CH0PREAM);
+       hdmi_writeb(hdmi, 0x16, HDMI_FC_CH1PREAM);
+       hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM);
+
+       /* Enable pixel clock and tmds data path */
+       clkdis = 0x7F;
+       clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
+       hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+
+       clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
+       hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+
+       /* Enable csc path */
+       if (is_color_space_conversion(hdmi)) {
+               clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
+               hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+       }
+}
+
+static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
+{
+       hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
+}
+
+/* Workaround to clear the overflow condition */
+static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
+{
+       int count;
+       u8 val;
+
+       /* TMDS software reset */
+       hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
+
+       val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
+       if (hdmi->dev_type == IMX6DL_HDMI) {
+               hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
+               return;
+       }
+
+       for (count = 0; count < 4; count++)
+               hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
+}
+
+static void hdmi_enable_overflow_interrupts(struct imx_hdmi *hdmi)
+{
+       hdmi_writeb(hdmi, 0, HDMI_FC_MASK2);
+       hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
+}
+
+static void hdmi_disable_overflow_interrupts(struct imx_hdmi *hdmi)
+{
+       hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
+                   HDMI_IH_MUTE_FC_STAT2);
+}
+
+static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
+{
+       int ret;
+
+       hdmi_disable_overflow_interrupts(hdmi);
+
+       hdmi->vic = drm_match_cea_mode(mode);
+
+       if (!hdmi->vic) {
+               dev_dbg(hdmi->dev, "Non-CEA mode used in HDMI\n");
+               hdmi->hdmi_data.video_mode.mdvi = true;
+       } else {
+               dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic);
+               hdmi->hdmi_data.video_mode.mdvi = false;
+       }
+
+       if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
+               (hdmi->vic == 21) || (hdmi->vic == 22) ||
+               (hdmi->vic == 2) || (hdmi->vic == 3) ||
+               (hdmi->vic == 17) || (hdmi->vic == 18))
+               hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
+       else
+               hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
+
+       if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
+               (hdmi->vic == 12) || (hdmi->vic == 13) ||
+               (hdmi->vic == 14) || (hdmi->vic == 15) ||
+               (hdmi->vic == 25) || (hdmi->vic == 26) ||
+               (hdmi->vic == 27) || (hdmi->vic == 28) ||
+               (hdmi->vic == 29) || (hdmi->vic == 30) ||
+               (hdmi->vic == 35) || (hdmi->vic == 36) ||
+               (hdmi->vic == 37) || (hdmi->vic == 38))
+               hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1;
+       else
+               hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
+
+       hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
+
+       /* TODO: Get input format from IPU (via FB driver interface) */
+       hdmi->hdmi_data.enc_in_format = RGB;
+
+       hdmi->hdmi_data.enc_out_format = RGB;
+
+       hdmi->hdmi_data.enc_color_depth = 8;
+       hdmi->hdmi_data.pix_repet_factor = 0;
+       hdmi->hdmi_data.hdcp_enable = 0;
+       hdmi->hdmi_data.video_mode.mdataenablepolarity = true;
+
+       /* HDMI Initialization Step B.1 */
+       hdmi_av_composer(hdmi, mode);
+
+       /* HDMI Initializateion Step B.2 */
+       ret = imx_hdmi_phy_init(hdmi);
+       if (ret)
+               return ret;
+
+       /* HDMI Initialization Step B.3 */
+       imx_hdmi_enable_video_path(hdmi);
+
+       /* not for DVI mode */
+       if (hdmi->hdmi_data.video_mode.mdvi)
+               dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
+       else {
+               dev_dbg(hdmi->dev, "%s CEA mode\n", __func__);
+
+               /* HDMI Initialization Step E - Configure audio */
+               hdmi_clk_regenerator_update_pixel_clock(hdmi);
+               hdmi_enable_audio_clk(hdmi);
+
+               /* HDMI Initialization Step F - Configure AVI InfoFrame */
+               hdmi_config_AVI(hdmi);
+       }
+
+       hdmi_video_packetize(hdmi);
+       hdmi_video_csc(hdmi);
+       hdmi_video_sample(hdmi);
+       hdmi_tx_hdcp_config(hdmi);
+
+       imx_hdmi_clear_overflow(hdmi);
+       if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi)
+               hdmi_enable_overflow_interrupts(hdmi);
+
+       return 0;
+}
+
+/* Wait until we are registered to enable interrupts */
+static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
+{
+       hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
+                   HDMI_PHY_I2CM_INT_ADDR);
+
+       hdmi_writeb(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
+                   HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
+                   HDMI_PHY_I2CM_CTLINT_ADDR);
+
+       /* enable cable hot plug irq */
+       hdmi_writeb(hdmi, (u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0);
+
+       /* Clear Hotplug interrupts */
+       hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
+
+       return 0;
+}
+
+static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
+{
+       u8 ih_mute;
+
+       /*
+        * Boot up defaults are:
+        * HDMI_IH_MUTE   = 0x03 (disabled)
+        * HDMI_IH_MUTE_* = 0x00 (enabled)
+        *
+        * Disable top level interrupt bits in HDMI block
+        */
+       ih_mute = hdmi_readb(hdmi, HDMI_IH_MUTE) |
+                 HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
+                 HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;
+
+       hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
+
+       /* by default mask all interrupts */
+       hdmi_writeb(hdmi, 0xff, HDMI_VP_MASK);
+       hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK0);
+       hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK1);
+       hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK2);
+       hdmi_writeb(hdmi, 0xff, HDMI_PHY_MASK0);
+       hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_INT_ADDR);
+       hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_CTLINT_ADDR);
+       hdmi_writeb(hdmi, 0xff, HDMI_AUD_INT);
+       hdmi_writeb(hdmi, 0xff, HDMI_AUD_SPDIFINT);
+       hdmi_writeb(hdmi, 0xff, HDMI_AUD_HBR_MASK);
+       hdmi_writeb(hdmi, 0xff, HDMI_GP_MASK);
+       hdmi_writeb(hdmi, 0xff, HDMI_A_APIINTMSK);
+       hdmi_writeb(hdmi, 0xff, HDMI_CEC_MASK);
+       hdmi_writeb(hdmi, 0xff, HDMI_I2CM_INT);
+       hdmi_writeb(hdmi, 0xff, HDMI_I2CM_CTLINT);
+
+       /* Disable interrupts in the IH_MUTE_* registers */
+       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT0);
+       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT1);
+       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT2);
+       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AS_STAT0);
+       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_PHY_STAT0);
+       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CM_STAT0);
+       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_CEC_STAT0);
+       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_VP_STAT0);
+       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CMPHY_STAT0);
+       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+
+       /* Enable top level interrupt bits in HDMI block */
+       ih_mute &= ~(HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
+                   HDMI_IH_MUTE_MUTE_ALL_INTERRUPT);
+       hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
+}
+
+static void imx_hdmi_poweron(struct imx_hdmi *hdmi)
+{
+       imx_hdmi_setup(hdmi, &hdmi->previous_mode);
+}
+
+static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
+{
+       imx_hdmi_phy_disable(hdmi);
+}
+
+static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
+                                                       *connector, bool force)
+{
+       struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+                                            connector);
+
+       return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
+               connector_status_connected : connector_status_disconnected;
+}
+
+static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
+{
+       struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+                                            connector);
+       struct edid *edid;
+       int ret;
+
+       if (!hdmi->ddc)
+               return 0;
+
+       edid = drm_get_edid(connector, hdmi->ddc);
+       if (edid) {
+               dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
+                       edid->width_cm, edid->height_cm);
+
+               drm_mode_connector_update_edid_property(connector, edid);
+               ret = drm_add_edid_modes(connector, edid);
+               kfree(edid);
+       } else {
+               dev_dbg(hdmi->dev, "failed to get edid\n");
+       }
+
+       return 0;
+}
+
+static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
+                                                          *connector)
+{
+       struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+                                            connector);
+
+       return &hdmi->encoder;
+}
+
+static void imx_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+                       struct drm_display_mode *mode,
+                       struct drm_display_mode *adjusted_mode)
+{
+       struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+
+       imx_hdmi_setup(hdmi, mode);
+
+       /* Store the display mode for plugin/DKMS poweron events */
+       memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
+}
+
+static bool imx_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
+                       const struct drm_display_mode *mode,
+                       struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void imx_hdmi_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static void imx_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+
+       if (mode)
+               imx_hdmi_poweroff(hdmi);
+       else
+               imx_hdmi_poweron(hdmi);
+}
+
+static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
+{
+       struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+
+       imx_hdmi_poweroff(hdmi);
+       imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
+}
+
+static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
+{
+       struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+       int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
+
+       imx_hdmi_set_ipu_di_mux(hdmi, mux);
+
+       imx_hdmi_poweron(hdmi);
+}
+
+static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
+       .destroy = imx_drm_encoder_destroy,
+};
+
+static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
+       .dpms = imx_hdmi_encoder_dpms,
+       .prepare = imx_hdmi_encoder_prepare,
+       .commit = imx_hdmi_encoder_commit,
+       .mode_set = imx_hdmi_encoder_mode_set,
+       .mode_fixup = imx_hdmi_encoder_mode_fixup,
+       .disable = imx_hdmi_encoder_disable,
+};
+
+static struct drm_connector_funcs imx_hdmi_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .detect = imx_hdmi_connector_detect,
+       .destroy = imx_drm_connector_destroy,
+};
+
+static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
+       .get_modes = imx_hdmi_connector_get_modes,
+       .best_encoder = imx_hdmi_connector_best_encoder,
+};
+
+static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
+{
+       struct imx_hdmi *hdmi = dev_id;
+       u8 intr_stat;
+
+       intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
+       if (intr_stat)
+               hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
+       return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
+}
+
+static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
+{
+       struct imx_hdmi *hdmi = dev_id;
+       u8 intr_stat;
+       u8 phy_int_pol;
+
+       intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
+
+       phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0);
+
+       if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
+               if (phy_int_pol & HDMI_PHY_HPD) {
+                       dev_dbg(hdmi->dev, "EVENT=plugin\n");
+
+                       hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
+
+                       imx_hdmi_poweron(hdmi);
+               } else {
+                       dev_dbg(hdmi->dev, "EVENT=plugout\n");
+
+                       hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
+                               HDMI_PHY_POL0);
+
+                       imx_hdmi_poweroff(hdmi);
+               }
+               drm_helper_hpd_irq_event(hdmi->connector.dev);
+       }
+
+       hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
+       hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
+
+       return IRQ_HANDLED;
+}
+
+static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
+{
+       int ret;
+
+       ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder,
+                                      hdmi->dev->of_node);
+       if (ret)
+               return ret;
+
+       hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
+       drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
+       drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
+                        DRM_MODE_ENCODER_TMDS);
+
+       drm_connector_helper_add(&hdmi->connector,
+                       &imx_hdmi_connector_helper_funcs);
+       drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
+                          DRM_MODE_CONNECTOR_HDMIA);
+
+       hdmi->connector.encoder = &hdmi->encoder;
+
+       drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder);
+
+       return 0;
+}
+
+static struct platform_device_id imx_hdmi_devtype[] = {
+       {
+               .name = "imx6q-hdmi",
+               .driver_data = IMX6Q_HDMI,
+       }, {
+               .name = "imx6dl-hdmi",
+               .driver_data = IMX6DL_HDMI,
+       }, { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype);
+
+static const struct of_device_id imx_hdmi_dt_ids[] = {
+{ .compatible = "fsl,imx6q-hdmi", .data = &imx_hdmi_devtype[IMX6Q_HDMI], },
+{ .compatible = "fsl,imx6dl-hdmi", .data = &imx_hdmi_devtype[IMX6DL_HDMI], },
+{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
+
+static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       const struct of_device_id *of_id =
+                               of_match_device(imx_hdmi_dt_ids, dev);
+       struct drm_device *drm = data;
+       struct device_node *np = dev->of_node;
+       struct device_node *ddc_node;
+       struct imx_hdmi *hdmi;
+       struct resource *iores;
+       int ret, irq;
+
+       hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
+       if (!hdmi)
+               return -ENOMEM;
+
+       hdmi->dev = dev;
+       hdmi->sample_rate = 48000;
+       hdmi->ratio = 100;
+
+       if (of_id) {
+               const struct platform_device_id *device_id = of_id->data;
+
+               hdmi->dev_type = device_id->driver_data;
+       }
+
+       ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
+       if (ddc_node) {
+               hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
+               if (!hdmi->ddc)
+                       dev_dbg(hdmi->dev, "failed to read ddc node\n");
+
+               of_node_put(ddc_node);
+       } else {
+               dev_dbg(hdmi->dev, "no ddc property found\n");
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
+                                       imx_hdmi_irq, IRQF_SHARED,
+                                       dev_name(dev), hdmi);
+       if (ret)
+               return ret;
+
+       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       hdmi->regs = devm_ioremap_resource(dev, iores);
+       if (IS_ERR(hdmi->regs))
+               return PTR_ERR(hdmi->regs);
+
+       hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
+       if (IS_ERR(hdmi->regmap))
+               return PTR_ERR(hdmi->regmap);
+
+       hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
+       if (IS_ERR(hdmi->isfr_clk)) {
+               ret = PTR_ERR(hdmi->isfr_clk);
+               dev_err(hdmi->dev,
+                       "Unable to get HDMI isfr clk: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(hdmi->isfr_clk);
+       if (ret) {
+               dev_err(hdmi->dev,
+                       "Cannot enable HDMI isfr clock: %d\n", ret);
+               return ret;
+       }
+
+       hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
+       if (IS_ERR(hdmi->iahb_clk)) {
+               ret = PTR_ERR(hdmi->iahb_clk);
+               dev_err(hdmi->dev,
+                       "Unable to get HDMI iahb clk: %d\n", ret);
+               goto err_isfr;
+       }
+
+       ret = clk_prepare_enable(hdmi->iahb_clk);
+       if (ret) {
+               dev_err(hdmi->dev,
+                       "Cannot enable HDMI iahb clock: %d\n", ret);
+               goto err_isfr;
+       }
+
+       /* Product and revision IDs */
+       dev_info(dev,
+               "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
+               hdmi_readb(hdmi, HDMI_DESIGN_ID),
+               hdmi_readb(hdmi, HDMI_REVISION_ID),
+               hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
+               hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
+
+       initialize_hdmi_ih_mutes(hdmi);
+
+       /*
+        * To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator
+        * N and cts values before enabling phy
+        */
+       hdmi_init_clk_regenerator(hdmi);
+
+       /*
+        * Configure registers related to HDMI interrupt
+        * generation before registering IRQ.
+        */
+       hdmi_writeb(hdmi, HDMI_PHY_HPD, HDMI_PHY_POL0);
+
+       /* Clear Hotplug interrupts */
+       hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
+
+       ret = imx_hdmi_fb_registered(hdmi);
+       if (ret)
+               goto err_iahb;
+
+       ret = imx_hdmi_register(drm, hdmi);
+       if (ret)
+               goto err_iahb;
+
+       /* Unmute interrupts */
+       hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
+
+       dev_set_drvdata(dev, hdmi);
+
+       return 0;
+
+err_iahb:
+       clk_disable_unprepare(hdmi->iahb_clk);
+err_isfr:
+       clk_disable_unprepare(hdmi->isfr_clk);
+
+       return ret;
+}
+
+static void imx_hdmi_unbind(struct device *dev, struct device *master,
+       void *data)
+{
+       struct imx_hdmi *hdmi = dev_get_drvdata(dev);
+
+       /* Disable all interrupts */
+       hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
+       hdmi->connector.funcs->destroy(&hdmi->connector);
+       hdmi->encoder.funcs->destroy(&hdmi->encoder);
+
+       clk_disable_unprepare(hdmi->iahb_clk);
+       clk_disable_unprepare(hdmi->isfr_clk);
+       i2c_put_adapter(hdmi->ddc);
+}
+
+static const struct component_ops hdmi_ops = {
+       .bind   = imx_hdmi_bind,
+       .unbind = imx_hdmi_unbind,
+};
+
+static int imx_hdmi_platform_probe(struct platform_device *pdev)
+{
+       return component_add(&pdev->dev, &hdmi_ops);
+}
+
+static int imx_hdmi_platform_remove(struct platform_device *pdev)
+{
+       component_del(&pdev->dev, &hdmi_ops);
+       return 0;
+}
+
+static struct platform_driver imx_hdmi_driver = {
+       .probe  = imx_hdmi_platform_probe,
+       .remove = imx_hdmi_platform_remove,
+       .driver = {
+               .name = "imx-hdmi",
+               .owner = THIS_MODULE,
+               .of_match_table = imx_hdmi_dt_ids,
+       },
+};
+
+module_platform_driver(imx_hdmi_driver);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-hdmi");
diff --git a/drivers/gpu/drm/imx/imx-hdmi.h b/drivers/gpu/drm/imx/imx-hdmi.h
new file mode 100644 (file)
index 0000000..39b6776
--- /dev/null
@@ -0,0 +1,1032 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __IMX_HDMI_H__
+#define __IMX_HDMI_H__
+
+/* Identification Registers */
+#define HDMI_DESIGN_ID                          0x0000
+#define HDMI_REVISION_ID                        0x0001
+#define HDMI_PRODUCT_ID0                        0x0002
+#define HDMI_PRODUCT_ID1                        0x0003
+#define HDMI_CONFIG0_ID                         0x0004
+#define HDMI_CONFIG1_ID                         0x0005
+#define HDMI_CONFIG2_ID                         0x0006
+#define HDMI_CONFIG3_ID                         0x0007
+
+/* Interrupt Registers */
+#define HDMI_IH_FC_STAT0                        0x0100
+#define HDMI_IH_FC_STAT1                        0x0101
+#define HDMI_IH_FC_STAT2                        0x0102
+#define HDMI_IH_AS_STAT0                        0x0103
+#define HDMI_IH_PHY_STAT0                       0x0104
+#define HDMI_IH_I2CM_STAT0                      0x0105
+#define HDMI_IH_CEC_STAT0                       0x0106
+#define HDMI_IH_VP_STAT0                        0x0107
+#define HDMI_IH_I2CMPHY_STAT0                   0x0108
+#define HDMI_IH_AHBDMAAUD_STAT0                 0x0109
+
+#define HDMI_IH_MUTE_FC_STAT0                   0x0180
+#define HDMI_IH_MUTE_FC_STAT1                   0x0181
+#define HDMI_IH_MUTE_FC_STAT2                   0x0182
+#define HDMI_IH_MUTE_AS_STAT0                   0x0183
+#define HDMI_IH_MUTE_PHY_STAT0                  0x0184
+#define HDMI_IH_MUTE_I2CM_STAT0                 0x0185
+#define HDMI_IH_MUTE_CEC_STAT0                  0x0186
+#define HDMI_IH_MUTE_VP_STAT0                   0x0187
+#define HDMI_IH_MUTE_I2CMPHY_STAT0              0x0188
+#define HDMI_IH_MUTE_AHBDMAAUD_STAT0            0x0189
+#define HDMI_IH_MUTE                            0x01FF
+
+/* Video Sample Registers */
+#define HDMI_TX_INVID0                          0x0200
+#define HDMI_TX_INSTUFFING                      0x0201
+#define HDMI_TX_GYDATA0                         0x0202
+#define HDMI_TX_GYDATA1                         0x0203
+#define HDMI_TX_RCRDATA0                        0x0204
+#define HDMI_TX_RCRDATA1                        0x0205
+#define HDMI_TX_BCBDATA0                        0x0206
+#define HDMI_TX_BCBDATA1                        0x0207
+
+/* Video Packetizer Registers */
+#define HDMI_VP_STATUS                          0x0800
+#define HDMI_VP_PR_CD                           0x0801
+#define HDMI_VP_STUFF                           0x0802
+#define HDMI_VP_REMAP                           0x0803
+#define HDMI_VP_CONF                            0x0804
+#define HDMI_VP_STAT                            0x0805
+#define HDMI_VP_INT                             0x0806
+#define HDMI_VP_MASK                            0x0807
+#define HDMI_VP_POL                             0x0808
+
+/* Frame Composer Registers */
+#define HDMI_FC_INVIDCONF                       0x1000
+#define HDMI_FC_INHACTV0                        0x1001
+#define HDMI_FC_INHACTV1                        0x1002
+#define HDMI_FC_INHBLANK0                       0x1003
+#define HDMI_FC_INHBLANK1                       0x1004
+#define HDMI_FC_INVACTV0                        0x1005
+#define HDMI_FC_INVACTV1                        0x1006
+#define HDMI_FC_INVBLANK                        0x1007
+#define HDMI_FC_HSYNCINDELAY0                   0x1008
+#define HDMI_FC_HSYNCINDELAY1                   0x1009
+#define HDMI_FC_HSYNCINWIDTH0                   0x100A
+#define HDMI_FC_HSYNCINWIDTH1                   0x100B
+#define HDMI_FC_VSYNCINDELAY                    0x100C
+#define HDMI_FC_VSYNCINWIDTH                    0x100D
+#define HDMI_FC_INFREQ0                         0x100E
+#define HDMI_FC_INFREQ1                         0x100F
+#define HDMI_FC_INFREQ2                         0x1010
+#define HDMI_FC_CTRLDUR                         0x1011
+#define HDMI_FC_EXCTRLDUR                       0x1012
+#define HDMI_FC_EXCTRLSPAC                      0x1013
+#define HDMI_FC_CH0PREAM                        0x1014
+#define HDMI_FC_CH1PREAM                        0x1015
+#define HDMI_FC_CH2PREAM                        0x1016
+#define HDMI_FC_AVICONF3                        0x1017
+#define HDMI_FC_GCP                             0x1018
+#define HDMI_FC_AVICONF0                        0x1019
+#define HDMI_FC_AVICONF1                        0x101A
+#define HDMI_FC_AVICONF2                        0x101B
+#define HDMI_FC_AVIVID                          0x101C
+#define HDMI_FC_AVIETB0                         0x101D
+#define HDMI_FC_AVIETB1                         0x101E
+#define HDMI_FC_AVISBB0                         0x101F
+#define HDMI_FC_AVISBB1                         0x1020
+#define HDMI_FC_AVIELB0                         0x1021
+#define HDMI_FC_AVIELB1                         0x1022
+#define HDMI_FC_AVISRB0                         0x1023
+#define HDMI_FC_AVISRB1                         0x1024
+#define HDMI_FC_AUDICONF0                       0x1025
+#define HDMI_FC_AUDICONF1                       0x1026
+#define HDMI_FC_AUDICONF2                       0x1027
+#define HDMI_FC_AUDICONF3                       0x1028
+#define HDMI_FC_VSDIEEEID0                      0x1029
+#define HDMI_FC_VSDSIZE                         0x102A
+#define HDMI_FC_VSDIEEEID1                      0x1030
+#define HDMI_FC_VSDIEEEID2                      0x1031
+#define HDMI_FC_VSDPAYLOAD0                     0x1032
+#define HDMI_FC_VSDPAYLOAD1                     0x1033
+#define HDMI_FC_VSDPAYLOAD2                     0x1034
+#define HDMI_FC_VSDPAYLOAD3                     0x1035
+#define HDMI_FC_VSDPAYLOAD4                     0x1036
+#define HDMI_FC_VSDPAYLOAD5                     0x1037
+#define HDMI_FC_VSDPAYLOAD6                     0x1038
+#define HDMI_FC_VSDPAYLOAD7                     0x1039
+#define HDMI_FC_VSDPAYLOAD8                     0x103A
+#define HDMI_FC_VSDPAYLOAD9                     0x103B
+#define HDMI_FC_VSDPAYLOAD10                    0x103C
+#define HDMI_FC_VSDPAYLOAD11                    0x103D
+#define HDMI_FC_VSDPAYLOAD12                    0x103E
+#define HDMI_FC_VSDPAYLOAD13                    0x103F
+#define HDMI_FC_VSDPAYLOAD14                    0x1040
+#define HDMI_FC_VSDPAYLOAD15                    0x1041
+#define HDMI_FC_VSDPAYLOAD16                    0x1042
+#define HDMI_FC_VSDPAYLOAD17                    0x1043
+#define HDMI_FC_VSDPAYLOAD18                    0x1044
+#define HDMI_FC_VSDPAYLOAD19                    0x1045
+#define HDMI_FC_VSDPAYLOAD20                    0x1046
+#define HDMI_FC_VSDPAYLOAD21                    0x1047
+#define HDMI_FC_VSDPAYLOAD22                    0x1048
+#define HDMI_FC_VSDPAYLOAD23                    0x1049
+#define HDMI_FC_SPDVENDORNAME0                  0x104A
+#define HDMI_FC_SPDVENDORNAME1                  0x104B
+#define HDMI_FC_SPDVENDORNAME2                  0x104C
+#define HDMI_FC_SPDVENDORNAME3                  0x104D
+#define HDMI_FC_SPDVENDORNAME4                  0x104E
+#define HDMI_FC_SPDVENDORNAME5                  0x104F
+#define HDMI_FC_SPDVENDORNAME6                  0x1050
+#define HDMI_FC_SPDVENDORNAME7                  0x1051
+#define HDMI_FC_SDPPRODUCTNAME0                 0x1052
+#define HDMI_FC_SDPPRODUCTNAME1                 0x1053
+#define HDMI_FC_SDPPRODUCTNAME2                 0x1054
+#define HDMI_FC_SDPPRODUCTNAME3                 0x1055
+#define HDMI_FC_SDPPRODUCTNAME4                 0x1056
+#define HDMI_FC_SDPPRODUCTNAME5                 0x1057
+#define HDMI_FC_SDPPRODUCTNAME6                 0x1058
+#define HDMI_FC_SDPPRODUCTNAME7                 0x1059
+#define HDMI_FC_SDPPRODUCTNAME8                 0x105A
+#define HDMI_FC_SDPPRODUCTNAME9                 0x105B
+#define HDMI_FC_SDPPRODUCTNAME10                0x105C
+#define HDMI_FC_SDPPRODUCTNAME11                0x105D
+#define HDMI_FC_SDPPRODUCTNAME12                0x105E
+#define HDMI_FC_SDPPRODUCTNAME13                0x105F
+#define HDMI_FC_SDPPRODUCTNAME14                0x1060
+#define HDMI_FC_SPDPRODUCTNAME15                0x1061
+#define HDMI_FC_SPDDEVICEINF                    0x1062
+#define HDMI_FC_AUDSCONF                        0x1063
+#define HDMI_FC_AUDSSTAT                        0x1064
+#define HDMI_FC_DATACH0FILL                     0x1070
+#define HDMI_FC_DATACH1FILL                     0x1071
+#define HDMI_FC_DATACH2FILL                     0x1072
+#define HDMI_FC_CTRLQHIGH                       0x1073
+#define HDMI_FC_CTRLQLOW                        0x1074
+#define HDMI_FC_ACP0                            0x1075
+#define HDMI_FC_ACP28                           0x1076
+#define HDMI_FC_ACP27                           0x1077
+#define HDMI_FC_ACP26                           0x1078
+#define HDMI_FC_ACP25                           0x1079
+#define HDMI_FC_ACP24                           0x107A
+#define HDMI_FC_ACP23                           0x107B
+#define HDMI_FC_ACP22                           0x107C
+#define HDMI_FC_ACP21                           0x107D
+#define HDMI_FC_ACP20                           0x107E
+#define HDMI_FC_ACP19                           0x107F
+#define HDMI_FC_ACP18                           0x1080
+#define HDMI_FC_ACP17                           0x1081
+#define HDMI_FC_ACP16                           0x1082
+#define HDMI_FC_ACP15                           0x1083
+#define HDMI_FC_ACP14                           0x1084
+#define HDMI_FC_ACP13                           0x1085
+#define HDMI_FC_ACP12                           0x1086
+#define HDMI_FC_ACP11                           0x1087
+#define HDMI_FC_ACP10                           0x1088
+#define HDMI_FC_ACP9                            0x1089
+#define HDMI_FC_ACP8                            0x108A
+#define HDMI_FC_ACP7                            0x108B
+#define HDMI_FC_ACP6                            0x108C
+#define HDMI_FC_ACP5                            0x108D
+#define HDMI_FC_ACP4                            0x108E
+#define HDMI_FC_ACP3                            0x108F
+#define HDMI_FC_ACP2                            0x1090
+#define HDMI_FC_ACP1                            0x1091
+#define HDMI_FC_ISCR1_0                         0x1092
+#define HDMI_FC_ISCR1_16                        0x1093
+#define HDMI_FC_ISCR1_15                        0x1094
+#define HDMI_FC_ISCR1_14                        0x1095
+#define HDMI_FC_ISCR1_13                        0x1096
+#define HDMI_FC_ISCR1_12                        0x1097
+#define HDMI_FC_ISCR1_11                        0x1098
+#define HDMI_FC_ISCR1_10                        0x1099
+#define HDMI_FC_ISCR1_9                         0x109A
+#define HDMI_FC_ISCR1_8                         0x109B
+#define HDMI_FC_ISCR1_7                         0x109C
+#define HDMI_FC_ISCR1_6                         0x109D
+#define HDMI_FC_ISCR1_5                         0x109E
+#define HDMI_FC_ISCR1_4                         0x109F
+#define HDMI_FC_ISCR1_3                         0x10A0
+#define HDMI_FC_ISCR1_2                         0x10A1
+#define HDMI_FC_ISCR1_1                         0x10A2
+#define HDMI_FC_ISCR2_15                        0x10A3
+#define HDMI_FC_ISCR2_14                        0x10A4
+#define HDMI_FC_ISCR2_13                        0x10A5
+#define HDMI_FC_ISCR2_12                        0x10A6
+#define HDMI_FC_ISCR2_11                        0x10A7
+#define HDMI_FC_ISCR2_10                        0x10A8
+#define HDMI_FC_ISCR2_9                         0x10A9
+#define HDMI_FC_ISCR2_8                         0x10AA
+#define HDMI_FC_ISCR2_7                         0x10AB
+#define HDMI_FC_ISCR2_6                         0x10AC
+#define HDMI_FC_ISCR2_5                         0x10AD
+#define HDMI_FC_ISCR2_4                         0x10AE
+#define HDMI_FC_ISCR2_3                         0x10AF
+#define HDMI_FC_ISCR2_2                         0x10B0
+#define HDMI_FC_ISCR2_1                         0x10B1
+#define HDMI_FC_ISCR2_0                         0x10B2
+#define HDMI_FC_DATAUTO0                        0x10B3
+#define HDMI_FC_DATAUTO1                        0x10B4
+#define HDMI_FC_DATAUTO2                        0x10B5
+#define HDMI_FC_DATMAN                          0x10B6
+#define HDMI_FC_DATAUTO3                        0x10B7
+#define HDMI_FC_RDRB0                           0x10B8
+#define HDMI_FC_RDRB1                           0x10B9
+#define HDMI_FC_RDRB2                           0x10BA
+#define HDMI_FC_RDRB3                           0x10BB
+#define HDMI_FC_RDRB4                           0x10BC
+#define HDMI_FC_RDRB5                           0x10BD
+#define HDMI_FC_RDRB6                           0x10BE
+#define HDMI_FC_RDRB7                           0x10BF
+#define HDMI_FC_STAT0                           0x10D0
+#define HDMI_FC_INT0                            0x10D1
+#define HDMI_FC_MASK0                           0x10D2
+#define HDMI_FC_POL0                            0x10D3
+#define HDMI_FC_STAT1                           0x10D4
+#define HDMI_FC_INT1                            0x10D5
+#define HDMI_FC_MASK1                           0x10D6
+#define HDMI_FC_POL1                            0x10D7
+#define HDMI_FC_STAT2                           0x10D8
+#define HDMI_FC_INT2                            0x10D9
+#define HDMI_FC_MASK2                           0x10DA
+#define HDMI_FC_POL2                            0x10DB
+#define HDMI_FC_PRCONF                          0x10E0
+
+#define HDMI_FC_GMD_STAT                        0x1100
+#define HDMI_FC_GMD_EN                          0x1101
+#define HDMI_FC_GMD_UP                          0x1102
+#define HDMI_FC_GMD_CONF                        0x1103
+#define HDMI_FC_GMD_HB                          0x1104
+#define HDMI_FC_GMD_PB0                         0x1105
+#define HDMI_FC_GMD_PB1                         0x1106
+#define HDMI_FC_GMD_PB2                         0x1107
+#define HDMI_FC_GMD_PB3                         0x1108
+#define HDMI_FC_GMD_PB4                         0x1109
+#define HDMI_FC_GMD_PB5                         0x110A
+#define HDMI_FC_GMD_PB6                         0x110B
+#define HDMI_FC_GMD_PB7                         0x110C
+#define HDMI_FC_GMD_PB8                         0x110D
+#define HDMI_FC_GMD_PB9                         0x110E
+#define HDMI_FC_GMD_PB10                        0x110F
+#define HDMI_FC_GMD_PB11                        0x1110
+#define HDMI_FC_GMD_PB12                        0x1111
+#define HDMI_FC_GMD_PB13                        0x1112
+#define HDMI_FC_GMD_PB14                        0x1113
+#define HDMI_FC_GMD_PB15                        0x1114
+#define HDMI_FC_GMD_PB16                        0x1115
+#define HDMI_FC_GMD_PB17                        0x1116
+#define HDMI_FC_GMD_PB18                        0x1117
+#define HDMI_FC_GMD_PB19                        0x1118
+#define HDMI_FC_GMD_PB20                        0x1119
+#define HDMI_FC_GMD_PB21                        0x111A
+#define HDMI_FC_GMD_PB22                        0x111B
+#define HDMI_FC_GMD_PB23                        0x111C
+#define HDMI_FC_GMD_PB24                        0x111D
+#define HDMI_FC_GMD_PB25                        0x111E
+#define HDMI_FC_GMD_PB26                        0x111F
+#define HDMI_FC_GMD_PB27                        0x1120
+
+#define HDMI_FC_DBGFORCE                        0x1200
+#define HDMI_FC_DBGAUD0CH0                      0x1201
+#define HDMI_FC_DBGAUD1CH0                      0x1202
+#define HDMI_FC_DBGAUD2CH0                      0x1203
+#define HDMI_FC_DBGAUD0CH1                      0x1204
+#define HDMI_FC_DBGAUD1CH1                      0x1205
+#define HDMI_FC_DBGAUD2CH1                      0x1206
+#define HDMI_FC_DBGAUD0CH2                      0x1207
+#define HDMI_FC_DBGAUD1CH2                      0x1208
+#define HDMI_FC_DBGAUD2CH2                      0x1209
+#define HDMI_FC_DBGAUD0CH3                      0x120A
+#define HDMI_FC_DBGAUD1CH3                      0x120B
+#define HDMI_FC_DBGAUD2CH3                      0x120C
+#define HDMI_FC_DBGAUD0CH4                      0x120D
+#define HDMI_FC_DBGAUD1CH4                      0x120E
+#define HDMI_FC_DBGAUD2CH4                      0x120F
+#define HDMI_FC_DBGAUD0CH5                      0x1210
+#define HDMI_FC_DBGAUD1CH5                      0x1211
+#define HDMI_FC_DBGAUD2CH5                      0x1212
+#define HDMI_FC_DBGAUD0CH6                      0x1213
+#define HDMI_FC_DBGAUD1CH6                      0x1214
+#define HDMI_FC_DBGAUD2CH6                      0x1215
+#define HDMI_FC_DBGAUD0CH7                      0x1216
+#define HDMI_FC_DBGAUD1CH7                      0x1217
+#define HDMI_FC_DBGAUD2CH7                      0x1218
+#define HDMI_FC_DBGTMDS0                        0x1219
+#define HDMI_FC_DBGTMDS1                        0x121A
+#define HDMI_FC_DBGTMDS2                        0x121B
+
+/* HDMI Source PHY Registers */
+#define HDMI_PHY_CONF0                          0x3000
+#define HDMI_PHY_TST0                           0x3001
+#define HDMI_PHY_TST1                           0x3002
+#define HDMI_PHY_TST2                           0x3003
+#define HDMI_PHY_STAT0                          0x3004
+#define HDMI_PHY_INT0                           0x3005
+#define HDMI_PHY_MASK0                          0x3006
+#define HDMI_PHY_POL0                           0x3007
+
+/* HDMI Master PHY Registers */
+#define HDMI_PHY_I2CM_SLAVE_ADDR                0x3020
+#define HDMI_PHY_I2CM_ADDRESS_ADDR              0x3021
+#define HDMI_PHY_I2CM_DATAO_1_ADDR              0x3022
+#define HDMI_PHY_I2CM_DATAO_0_ADDR              0x3023
+#define HDMI_PHY_I2CM_DATAI_1_ADDR              0x3024
+#define HDMI_PHY_I2CM_DATAI_0_ADDR              0x3025
+#define HDMI_PHY_I2CM_OPERATION_ADDR            0x3026
+#define HDMI_PHY_I2CM_INT_ADDR                  0x3027
+#define HDMI_PHY_I2CM_CTLINT_ADDR               0x3028
+#define HDMI_PHY_I2CM_DIV_ADDR                  0x3029
+#define HDMI_PHY_I2CM_SOFTRSTZ_ADDR             0x302a
+#define HDMI_PHY_I2CM_SS_SCL_HCNT_1_ADDR        0x302b
+#define HDMI_PHY_I2CM_SS_SCL_HCNT_0_ADDR        0x302c
+#define HDMI_PHY_I2CM_SS_SCL_LCNT_1_ADDR        0x302d
+#define HDMI_PHY_I2CM_SS_SCL_LCNT_0_ADDR        0x302e
+#define HDMI_PHY_I2CM_FS_SCL_HCNT_1_ADDR        0x302f
+#define HDMI_PHY_I2CM_FS_SCL_HCNT_0_ADDR        0x3030
+#define HDMI_PHY_I2CM_FS_SCL_LCNT_1_ADDR        0x3031
+#define HDMI_PHY_I2CM_FS_SCL_LCNT_0_ADDR        0x3032
+
+/* Audio Sampler Registers */
+#define HDMI_AUD_CONF0                          0x3100
+#define HDMI_AUD_CONF1                          0x3101
+#define HDMI_AUD_INT                            0x3102
+#define HDMI_AUD_CONF2                          0x3103
+#define HDMI_AUD_N1                             0x3200
+#define HDMI_AUD_N2                             0x3201
+#define HDMI_AUD_N3                             0x3202
+#define HDMI_AUD_CTS1                           0x3203
+#define HDMI_AUD_CTS2                           0x3204
+#define HDMI_AUD_CTS3                           0x3205
+#define HDMI_AUD_INPUTCLKFS                     0x3206
+#define HDMI_AUD_SPDIFINT                      0x3302
+#define HDMI_AUD_CONF0_HBR                      0x3400
+#define HDMI_AUD_HBR_STATUS                     0x3401
+#define HDMI_AUD_HBR_INT                        0x3402
+#define HDMI_AUD_HBR_POL                        0x3403
+#define HDMI_AUD_HBR_MASK                       0x3404
+
+/*
+ * Generic Parallel Audio Interface Registers
+ * Not used as GPAUD interface is not enabled in hw
+ */
+#define HDMI_GP_CONF0                           0x3500
+#define HDMI_GP_CONF1                           0x3501
+#define HDMI_GP_CONF2                           0x3502
+#define HDMI_GP_STAT                            0x3503
+#define HDMI_GP_INT                             0x3504
+#define HDMI_GP_MASK                            0x3505
+#define HDMI_GP_POL                             0x3506
+
+/* Audio DMA Registers */
+#define HDMI_AHB_DMA_CONF0                      0x3600
+#define HDMI_AHB_DMA_START                      0x3601
+#define HDMI_AHB_DMA_STOP                       0x3602
+#define HDMI_AHB_DMA_THRSLD                     0x3603
+#define HDMI_AHB_DMA_STRADDR0                   0x3604
+#define HDMI_AHB_DMA_STRADDR1                   0x3605
+#define HDMI_AHB_DMA_STRADDR2                   0x3606
+#define HDMI_AHB_DMA_STRADDR3                   0x3607
+#define HDMI_AHB_DMA_STPADDR0                   0x3608
+#define HDMI_AHB_DMA_STPADDR1                   0x3609
+#define HDMI_AHB_DMA_STPADDR2                   0x360a
+#define HDMI_AHB_DMA_STPADDR3                   0x360b
+#define HDMI_AHB_DMA_BSTADDR0                   0x360c
+#define HDMI_AHB_DMA_BSTADDR1                   0x360d
+#define HDMI_AHB_DMA_BSTADDR2                   0x360e
+#define HDMI_AHB_DMA_BSTADDR3                   0x360f
+#define HDMI_AHB_DMA_MBLENGTH0                  0x3610
+#define HDMI_AHB_DMA_MBLENGTH1                  0x3611
+#define HDMI_AHB_DMA_STAT                       0x3612
+#define HDMI_AHB_DMA_INT                        0x3613
+#define HDMI_AHB_DMA_MASK                       0x3614
+#define HDMI_AHB_DMA_POL                        0x3615
+#define HDMI_AHB_DMA_CONF1                      0x3616
+#define HDMI_AHB_DMA_BUFFSTAT                   0x3617
+#define HDMI_AHB_DMA_BUFFINT                    0x3618
+#define HDMI_AHB_DMA_BUFFMASK                   0x3619
+#define HDMI_AHB_DMA_BUFFPOL                    0x361a
+
+/* Main Controller Registers */
+#define HDMI_MC_SFRDIV                          0x4000
+#define HDMI_MC_CLKDIS                          0x4001
+#define HDMI_MC_SWRSTZ                          0x4002
+#define HDMI_MC_OPCTRL                          0x4003
+#define HDMI_MC_FLOWCTRL                        0x4004
+#define HDMI_MC_PHYRSTZ                         0x4005
+#define HDMI_MC_LOCKONCLOCK                     0x4006
+#define HDMI_MC_HEACPHY_RST                     0x4007
+
+/* Color Space  Converter Registers */
+#define HDMI_CSC_CFG                            0x4100
+#define HDMI_CSC_SCALE                          0x4101
+#define HDMI_CSC_COEF_A1_MSB                    0x4102
+#define HDMI_CSC_COEF_A1_LSB                    0x4103
+#define HDMI_CSC_COEF_A2_MSB                    0x4104
+#define HDMI_CSC_COEF_A2_LSB                    0x4105
+#define HDMI_CSC_COEF_A3_MSB                    0x4106
+#define HDMI_CSC_COEF_A3_LSB                    0x4107
+#define HDMI_CSC_COEF_A4_MSB                    0x4108
+#define HDMI_CSC_COEF_A4_LSB                    0x4109
+#define HDMI_CSC_COEF_B1_MSB                    0x410A
+#define HDMI_CSC_COEF_B1_LSB                    0x410B
+#define HDMI_CSC_COEF_B2_MSB                    0x410C
+#define HDMI_CSC_COEF_B2_LSB                    0x410D
+#define HDMI_CSC_COEF_B3_MSB                    0x410E
+#define HDMI_CSC_COEF_B3_LSB                    0x410F
+#define HDMI_CSC_COEF_B4_MSB                    0x4110
+#define HDMI_CSC_COEF_B4_LSB                    0x4111
+#define HDMI_CSC_COEF_C1_MSB                    0x4112
+#define HDMI_CSC_COEF_C1_LSB                    0x4113
+#define HDMI_CSC_COEF_C2_MSB                    0x4114
+#define HDMI_CSC_COEF_C2_LSB                    0x4115
+#define HDMI_CSC_COEF_C3_MSB                    0x4116
+#define HDMI_CSC_COEF_C3_LSB                    0x4117
+#define HDMI_CSC_COEF_C4_MSB                    0x4118
+#define HDMI_CSC_COEF_C4_LSB                    0x4119
+
+/* HDCP Encryption Engine Registers */
+#define HDMI_A_HDCPCFG0                         0x5000
+#define HDMI_A_HDCPCFG1                         0x5001
+#define HDMI_A_HDCPOBS0                         0x5002
+#define HDMI_A_HDCPOBS1                         0x5003
+#define HDMI_A_HDCPOBS2                         0x5004
+#define HDMI_A_HDCPOBS3                         0x5005
+#define HDMI_A_APIINTCLR                        0x5006
+#define HDMI_A_APIINTSTAT                       0x5007
+#define HDMI_A_APIINTMSK                        0x5008
+#define HDMI_A_VIDPOLCFG                        0x5009
+#define HDMI_A_OESSWCFG                         0x500A
+#define HDMI_A_TIMER1SETUP0                     0x500B
+#define HDMI_A_TIMER1SETUP1                     0x500C
+#define HDMI_A_TIMER2SETUP0                     0x500D
+#define HDMI_A_TIMER2SETUP1                     0x500E
+#define HDMI_A_100MSCFG                         0x500F
+#define HDMI_A_2SCFG0                           0x5010
+#define HDMI_A_2SCFG1                           0x5011
+#define HDMI_A_5SCFG0                           0x5012
+#define HDMI_A_5SCFG1                           0x5013
+#define HDMI_A_SRMVERLSB                        0x5014
+#define HDMI_A_SRMVERMSB                        0x5015
+#define HDMI_A_SRMCTRL                          0x5016
+#define HDMI_A_SFRSETUP                         0x5017
+#define HDMI_A_I2CHSETUP                        0x5018
+#define HDMI_A_INTSETUP                         0x5019
+#define HDMI_A_PRESETUP                         0x501A
+#define HDMI_A_SRM_BASE                         0x5020
+
+/* CEC Engine Registers */
+#define HDMI_CEC_CTRL                           0x7D00
+#define HDMI_CEC_STAT                           0x7D01
+#define HDMI_CEC_MASK                           0x7D02
+#define HDMI_CEC_POLARITY                       0x7D03
+#define HDMI_CEC_INT                            0x7D04
+#define HDMI_CEC_ADDR_L                         0x7D05
+#define HDMI_CEC_ADDR_H                         0x7D06
+#define HDMI_CEC_TX_CNT                         0x7D07
+#define HDMI_CEC_RX_CNT                         0x7D08
+#define HDMI_CEC_TX_DATA0                       0x7D10
+#define HDMI_CEC_TX_DATA1                       0x7D11
+#define HDMI_CEC_TX_DATA2                       0x7D12
+#define HDMI_CEC_TX_DATA3                       0x7D13
+#define HDMI_CEC_TX_DATA4                       0x7D14
+#define HDMI_CEC_TX_DATA5                       0x7D15
+#define HDMI_CEC_TX_DATA6                       0x7D16
+#define HDMI_CEC_TX_DATA7                       0x7D17
+#define HDMI_CEC_TX_DATA8                       0x7D18
+#define HDMI_CEC_TX_DATA9                       0x7D19
+#define HDMI_CEC_TX_DATA10                      0x7D1a
+#define HDMI_CEC_TX_DATA11                      0x7D1b
+#define HDMI_CEC_TX_DATA12                      0x7D1c
+#define HDMI_CEC_TX_DATA13                      0x7D1d
+#define HDMI_CEC_TX_DATA14                      0x7D1e
+#define HDMI_CEC_TX_DATA15                      0x7D1f
+#define HDMI_CEC_RX_DATA0                       0x7D20
+#define HDMI_CEC_RX_DATA1                       0x7D21
+#define HDMI_CEC_RX_DATA2                       0x7D22
+#define HDMI_CEC_RX_DATA3                       0x7D23
+#define HDMI_CEC_RX_DATA4                       0x7D24
+#define HDMI_CEC_RX_DATA5                       0x7D25
+#define HDMI_CEC_RX_DATA6                       0x7D26
+#define HDMI_CEC_RX_DATA7                       0x7D27
+#define HDMI_CEC_RX_DATA8                       0x7D28
+#define HDMI_CEC_RX_DATA9                       0x7D29
+#define HDMI_CEC_RX_DATA10                      0x7D2a
+#define HDMI_CEC_RX_DATA11                      0x7D2b
+#define HDMI_CEC_RX_DATA12                      0x7D2c
+#define HDMI_CEC_RX_DATA13                      0x7D2d
+#define HDMI_CEC_RX_DATA14                      0x7D2e
+#define HDMI_CEC_RX_DATA15                      0x7D2f
+#define HDMI_CEC_LOCK                           0x7D30
+#define HDMI_CEC_WKUPCTRL                       0x7D31
+
+/* I2C Master Registers (E-DDC) */
+#define HDMI_I2CM_SLAVE                         0x7E00
+#define HDMI_I2CMESS                            0x7E01
+#define HDMI_I2CM_DATAO                         0x7E02
+#define HDMI_I2CM_DATAI                         0x7E03
+#define HDMI_I2CM_OPERATION                     0x7E04
+#define HDMI_I2CM_INT                           0x7E05
+#define HDMI_I2CM_CTLINT                        0x7E06
+#define HDMI_I2CM_DIV                           0x7E07
+#define HDMI_I2CM_SEGADDR                       0x7E08
+#define HDMI_I2CM_SOFTRSTZ                      0x7E09
+#define HDMI_I2CM_SEGPTR                        0x7E0A
+#define HDMI_I2CM_SS_SCL_HCNT_1_ADDR            0x7E0B
+#define HDMI_I2CM_SS_SCL_HCNT_0_ADDR            0x7E0C
+#define HDMI_I2CM_SS_SCL_LCNT_1_ADDR            0x7E0D
+#define HDMI_I2CM_SS_SCL_LCNT_0_ADDR            0x7E0E
+#define HDMI_I2CM_FS_SCL_HCNT_1_ADDR            0x7E0F
+#define HDMI_I2CM_FS_SCL_HCNT_0_ADDR            0x7E10
+#define HDMI_I2CM_FS_SCL_LCNT_1_ADDR            0x7E11
+#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR            0x7E12
+
+enum {
+/* IH_FC_INT2 field values */
+       HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03,
+       HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
+       HDMI_IH_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* IH_FC_STAT2 field values */
+       HDMI_IH_FC_STAT2_OVERFLOW_MASK = 0x03,
+       HDMI_IH_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
+       HDMI_IH_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* IH_PHY_STAT0 field values */
+       HDMI_IH_PHY_STAT0_RX_SENSE3 = 0x20,
+       HDMI_IH_PHY_STAT0_RX_SENSE2 = 0x10,
+       HDMI_IH_PHY_STAT0_RX_SENSE1 = 0x8,
+       HDMI_IH_PHY_STAT0_RX_SENSE0 = 0x4,
+       HDMI_IH_PHY_STAT0_TX_PHY_LOCK = 0x2,
+       HDMI_IH_PHY_STAT0_HPD = 0x1,
+
+/* IH_MUTE_I2CMPHY_STAT0 field values */
+       HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYDONE = 0x2,
+       HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYERROR = 0x1,
+
+/* IH_AHBDMAAUD_STAT0 field values */
+       HDMI_IH_AHBDMAAUD_STAT0_ERROR = 0x20,
+       HDMI_IH_AHBDMAAUD_STAT0_LOST = 0x10,
+       HDMI_IH_AHBDMAAUD_STAT0_RETRY = 0x08,
+       HDMI_IH_AHBDMAAUD_STAT0_DONE = 0x04,
+       HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = 0x02,
+       HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01,
+
+/* IH_MUTE_FC_STAT2 field values */
+       HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK = 0x03,
+       HDMI_IH_MUTE_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
+       HDMI_IH_MUTE_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* IH_MUTE_AHBDMAAUD_STAT0 field values */
+       HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = 0x20,
+       HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = 0x10,
+       HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = 0x08,
+       HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = 0x04,
+       HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = 0x02,
+       HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01,
+
+/* IH_MUTE field values */
+       HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT = 0x2,
+       HDMI_IH_MUTE_MUTE_ALL_INTERRUPT = 0x1,
+
+/* TX_INVID0 field values */
+       HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_MASK = 0x80,
+       HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_ENABLE = 0x80,
+       HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE = 0x00,
+       HDMI_TX_INVID0_VIDEO_MAPPING_MASK = 0x1F,
+       HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET = 0,
+
+/* TX_INSTUFFING field values */
+       HDMI_TX_INSTUFFING_BDBDATA_STUFFING_MASK = 0x4,
+       HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE = 0x4,
+       HDMI_TX_INSTUFFING_BDBDATA_STUFFING_DISABLE = 0x0,
+       HDMI_TX_INSTUFFING_RCRDATA_STUFFING_MASK = 0x2,
+       HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE = 0x2,
+       HDMI_TX_INSTUFFING_RCRDATA_STUFFING_DISABLE = 0x0,
+       HDMI_TX_INSTUFFING_GYDATA_STUFFING_MASK = 0x1,
+       HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE = 0x1,
+       HDMI_TX_INSTUFFING_GYDATA_STUFFING_DISABLE = 0x0,
+
+/* VP_PR_CD field values */
+       HDMI_VP_PR_CD_COLOR_DEPTH_MASK = 0xF0,
+       HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET = 4,
+       HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK = 0x0F,
+       HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET = 0,
+
+/* VP_STUFF field values */
+       HDMI_VP_STUFF_IDEFAULT_PHASE_MASK = 0x20,
+       HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET = 5,
+       HDMI_VP_STUFF_IFIX_PP_TO_LAST_MASK = 0x10,
+       HDMI_VP_STUFF_IFIX_PP_TO_LAST_OFFSET = 4,
+       HDMI_VP_STUFF_ICX_GOTO_P0_ST_MASK = 0x8,
+       HDMI_VP_STUFF_ICX_GOTO_P0_ST_OFFSET = 3,
+       HDMI_VP_STUFF_YCC422_STUFFING_MASK = 0x4,
+       HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE = 0x4,
+       HDMI_VP_STUFF_YCC422_STUFFING_DIRECT_MODE = 0x0,
+       HDMI_VP_STUFF_PP_STUFFING_MASK = 0x2,
+       HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE = 0x2,
+       HDMI_VP_STUFF_PP_STUFFING_DIRECT_MODE = 0x0,
+       HDMI_VP_STUFF_PR_STUFFING_MASK = 0x1,
+       HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE = 0x1,
+       HDMI_VP_STUFF_PR_STUFFING_DIRECT_MODE = 0x0,
+
+/* VP_CONF field values */
+       HDMI_VP_CONF_BYPASS_EN_MASK = 0x40,
+       HDMI_VP_CONF_BYPASS_EN_ENABLE = 0x40,
+       HDMI_VP_CONF_BYPASS_EN_DISABLE = 0x00,
+       HDMI_VP_CONF_PP_EN_ENMASK = 0x20,
+       HDMI_VP_CONF_PP_EN_ENABLE = 0x20,
+       HDMI_VP_CONF_PP_EN_DISABLE = 0x00,
+       HDMI_VP_CONF_PR_EN_MASK = 0x10,
+       HDMI_VP_CONF_PR_EN_ENABLE = 0x10,
+       HDMI_VP_CONF_PR_EN_DISABLE = 0x00,
+       HDMI_VP_CONF_YCC422_EN_MASK = 0x8,
+       HDMI_VP_CONF_YCC422_EN_ENABLE = 0x8,
+       HDMI_VP_CONF_YCC422_EN_DISABLE = 0x0,
+       HDMI_VP_CONF_BYPASS_SELECT_MASK = 0x4,
+       HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER = 0x4,
+       HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER = 0x0,
+       HDMI_VP_CONF_OUTPUT_SELECTOR_MASK = 0x3,
+       HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS = 0x3,
+       HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422 = 0x1,
+       HDMI_VP_CONF_OUTPUT_SELECTOR_PP = 0x0,
+
+/* VP_REMAP field values */
+       HDMI_VP_REMAP_MASK = 0x3,
+       HDMI_VP_REMAP_YCC422_24bit = 0x2,
+       HDMI_VP_REMAP_YCC422_20bit = 0x1,
+       HDMI_VP_REMAP_YCC422_16bit = 0x0,
+
+/* FC_INVIDCONF field values */
+       HDMI_FC_INVIDCONF_HDCP_KEEPOUT_MASK = 0x80,
+       HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE = 0x80,
+       HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE = 0x00,
+       HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_MASK = 0x40,
+       HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH = 0x40,
+       HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW = 0x00,
+       HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_MASK = 0x20,
+       HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH = 0x20,
+       HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW = 0x00,
+       HDMI_FC_INVIDCONF_DE_IN_POLARITY_MASK = 0x10,
+       HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH = 0x10,
+       HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW = 0x00,
+       HDMI_FC_INVIDCONF_DVI_MODEZ_MASK = 0x8,
+       HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE = 0x8,
+       HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE = 0x0,
+       HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_MASK = 0x2,
+       HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH = 0x2,
+       HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW = 0x0,
+       HDMI_FC_INVIDCONF_IN_I_P_MASK = 0x1,
+       HDMI_FC_INVIDCONF_IN_I_P_INTERLACED = 0x1,
+       HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE = 0x0,
+
+/* FC_AUDICONF0 field values */
+       HDMI_FC_AUDICONF0_CC_OFFSET = 4,
+       HDMI_FC_AUDICONF0_CC_MASK = 0x70,
+       HDMI_FC_AUDICONF0_CT_OFFSET = 0,
+       HDMI_FC_AUDICONF0_CT_MASK = 0xF,
+
+/* FC_AUDICONF1 field values */
+       HDMI_FC_AUDICONF1_SS_OFFSET = 3,
+       HDMI_FC_AUDICONF1_SS_MASK = 0x18,
+       HDMI_FC_AUDICONF1_SF_OFFSET = 0,
+       HDMI_FC_AUDICONF1_SF_MASK = 0x7,
+
+/* FC_AUDICONF3 field values */
+       HDMI_FC_AUDICONF3_LFEPBL_OFFSET = 5,
+       HDMI_FC_AUDICONF3_LFEPBL_MASK = 0x60,
+       HDMI_FC_AUDICONF3_DM_INH_OFFSET = 4,
+       HDMI_FC_AUDICONF3_DM_INH_MASK = 0x10,
+       HDMI_FC_AUDICONF3_LSV_OFFSET = 0,
+       HDMI_FC_AUDICONF3_LSV_MASK = 0xF,
+
+/* FC_AUDSCHNLS0 field values */
+       HDMI_FC_AUDSCHNLS0_CGMSA_OFFSET = 4,
+       HDMI_FC_AUDSCHNLS0_CGMSA_MASK = 0x30,
+       HDMI_FC_AUDSCHNLS0_COPYRIGHT_OFFSET = 0,
+       HDMI_FC_AUDSCHNLS0_COPYRIGHT_MASK = 0x01,
+
+/* FC_AUDSCHNLS3-6 field values */
+       HDMI_FC_AUDSCHNLS3_OIEC_CH0_OFFSET = 0,
+       HDMI_FC_AUDSCHNLS3_OIEC_CH0_MASK = 0x0f,
+       HDMI_FC_AUDSCHNLS3_OIEC_CH1_OFFSET = 4,
+       HDMI_FC_AUDSCHNLS3_OIEC_CH1_MASK = 0xf0,
+       HDMI_FC_AUDSCHNLS4_OIEC_CH2_OFFSET = 0,
+       HDMI_FC_AUDSCHNLS4_OIEC_CH2_MASK = 0x0f,
+       HDMI_FC_AUDSCHNLS4_OIEC_CH3_OFFSET = 4,
+       HDMI_FC_AUDSCHNLS4_OIEC_CH3_MASK = 0xf0,
+
+       HDMI_FC_AUDSCHNLS5_OIEC_CH0_OFFSET = 0,
+       HDMI_FC_AUDSCHNLS5_OIEC_CH0_MASK = 0x0f,
+       HDMI_FC_AUDSCHNLS5_OIEC_CH1_OFFSET = 4,
+       HDMI_FC_AUDSCHNLS5_OIEC_CH1_MASK = 0xf0,
+       HDMI_FC_AUDSCHNLS6_OIEC_CH2_OFFSET = 0,
+       HDMI_FC_AUDSCHNLS6_OIEC_CH2_MASK = 0x0f,
+       HDMI_FC_AUDSCHNLS6_OIEC_CH3_OFFSET = 4,
+       HDMI_FC_AUDSCHNLS6_OIEC_CH3_MASK = 0xf0,
+
+/* HDMI_FC_AUDSCHNLS7 field values */
+       HDMI_FC_AUDSCHNLS7_ACCURACY_OFFSET = 4,
+       HDMI_FC_AUDSCHNLS7_ACCURACY_MASK = 0x30,
+
+/* HDMI_FC_AUDSCHNLS8 field values */
+       HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_MASK = 0xf0,
+       HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_OFFSET = 4,
+       HDMI_FC_AUDSCHNLS8_WORDLEGNTH_MASK = 0x0f,
+       HDMI_FC_AUDSCHNLS8_WORDLEGNTH_OFFSET = 0,
+
+/* FC_AUDSCONF field values */
+       HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_MASK = 0xF0,
+       HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_OFFSET = 4,
+       HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK = 0x1,
+       HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_OFFSET = 0,
+       HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1 = 0x1,
+       HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0 = 0x0,
+
+/* FC_STAT2 field values */
+       HDMI_FC_STAT2_OVERFLOW_MASK = 0x03,
+       HDMI_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
+       HDMI_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* FC_INT2 field values */
+       HDMI_FC_INT2_OVERFLOW_MASK = 0x03,
+       HDMI_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
+       HDMI_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* FC_MASK2 field values */
+       HDMI_FC_MASK2_OVERFLOW_MASK = 0x03,
+       HDMI_FC_MASK2_LOW_PRIORITY_OVERFLOW = 0x02,
+       HDMI_FC_MASK2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* FC_PRCONF field values */
+       HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK = 0xF0,
+       HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET = 4,
+       HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK = 0x0F,
+       HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET = 0,
+
+/* FC_AVICONF0-FC_AVICONF3 field values */
+       HDMI_FC_AVICONF0_PIX_FMT_MASK = 0x03,
+       HDMI_FC_AVICONF0_PIX_FMT_RGB = 0x00,
+       HDMI_FC_AVICONF0_PIX_FMT_YCBCR422 = 0x01,
+       HDMI_FC_AVICONF0_PIX_FMT_YCBCR444 = 0x02,
+       HDMI_FC_AVICONF0_ACTIVE_FMT_MASK = 0x40,
+       HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT = 0x40,
+       HDMI_FC_AVICONF0_ACTIVE_FMT_NO_INFO = 0x00,
+       HDMI_FC_AVICONF0_BAR_DATA_MASK = 0x0C,
+       HDMI_FC_AVICONF0_BAR_DATA_NO_DATA = 0x00,
+       HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR = 0x04,
+       HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR = 0x08,
+       HDMI_FC_AVICONF0_BAR_DATA_VERT_HORIZ_BAR = 0x0C,
+       HDMI_FC_AVICONF0_SCAN_INFO_MASK = 0x30,
+       HDMI_FC_AVICONF0_SCAN_INFO_OVERSCAN = 0x10,
+       HDMI_FC_AVICONF0_SCAN_INFO_UNDERSCAN = 0x20,
+       HDMI_FC_AVICONF0_SCAN_INFO_NODATA = 0x00,
+
+       HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_MASK = 0x0F,
+       HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_USE_CODED = 0x08,
+       HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3 = 0x09,
+       HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9 = 0x0A,
+       HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_14_9 = 0x0B,
+       HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_MASK = 0x30,
+       HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_NO_DATA = 0x00,
+       HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3 = 0x10,
+       HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9 = 0x20,
+       HDMI_FC_AVICONF1_COLORIMETRY_MASK = 0xC0,
+       HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA = 0x00,
+       HDMI_FC_AVICONF1_COLORIMETRY_SMPTE = 0x40,
+       HDMI_FC_AVICONF1_COLORIMETRY_ITUR = 0x80,
+       HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO = 0xC0,
+
+       HDMI_FC_AVICONF2_SCALING_MASK = 0x03,
+       HDMI_FC_AVICONF2_SCALING_NONE = 0x00,
+       HDMI_FC_AVICONF2_SCALING_HORIZ = 0x01,
+       HDMI_FC_AVICONF2_SCALING_VERT = 0x02,
+       HDMI_FC_AVICONF2_SCALING_HORIZ_VERT = 0x03,
+       HDMI_FC_AVICONF2_RGB_QUANT_MASK = 0x0C,
+       HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT = 0x00,
+       HDMI_FC_AVICONF2_RGB_QUANT_LIMITED_RANGE = 0x04,
+       HDMI_FC_AVICONF2_RGB_QUANT_FULL_RANGE = 0x08,
+       HDMI_FC_AVICONF2_EXT_COLORIMETRY_MASK = 0x70,
+       HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601 = 0x00,
+       HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709 = 0x10,
+       HDMI_FC_AVICONF2_EXT_COLORIMETRY_SYCC601 = 0x20,
+       HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_YCC601 = 0x30,
+       HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_RGB = 0x40,
+       HDMI_FC_AVICONF2_IT_CONTENT_MASK = 0x80,
+       HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA = 0x00,
+       HDMI_FC_AVICONF2_IT_CONTENT_VALID = 0x80,
+
+       HDMI_FC_AVICONF3_IT_CONTENT_TYPE_MASK = 0x03,
+       HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS = 0x00,
+       HDMI_FC_AVICONF3_IT_CONTENT_TYPE_PHOTO = 0x01,
+       HDMI_FC_AVICONF3_IT_CONTENT_TYPE_CINEMA = 0x02,
+       HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GAME = 0x03,
+       HDMI_FC_AVICONF3_QUANT_RANGE_MASK = 0x0C,
+       HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED = 0x00,
+       HDMI_FC_AVICONF3_QUANT_RANGE_FULL = 0x04,
+
+/* FC_DBGFORCE field values */
+       HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10,
+       HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1,
+
+/* PHY_CONF0 field values */
+       HDMI_PHY_CONF0_PDZ_MASK = 0x80,
+       HDMI_PHY_CONF0_PDZ_OFFSET = 7,
+       HDMI_PHY_CONF0_ENTMDS_MASK = 0x40,
+       HDMI_PHY_CONF0_ENTMDS_OFFSET = 6,
+       HDMI_PHY_CONF0_SPARECTRL = 0x20,
+       HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10,
+       HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4,
+       HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8,
+       HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET = 3,
+       HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_MASK = 0x4,
+       HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_OFFSET = 2,
+       HDMI_PHY_CONF0_SELDATAENPOL_MASK = 0x2,
+       HDMI_PHY_CONF0_SELDATAENPOL_OFFSET = 1,
+       HDMI_PHY_CONF0_SELDIPIF_MASK = 0x1,
+       HDMI_PHY_CONF0_SELDIPIF_OFFSET = 0,
+
+/* PHY_TST0 field values */
+       HDMI_PHY_TST0_TSTCLR_MASK = 0x20,
+       HDMI_PHY_TST0_TSTCLR_OFFSET = 5,
+       HDMI_PHY_TST0_TSTEN_MASK = 0x10,
+       HDMI_PHY_TST0_TSTEN_OFFSET = 4,
+       HDMI_PHY_TST0_TSTCLK_MASK = 0x1,
+       HDMI_PHY_TST0_TSTCLK_OFFSET = 0,
+
+/* PHY_STAT0 field values */
+       HDMI_PHY_RX_SENSE3 = 0x80,
+       HDMI_PHY_RX_SENSE2 = 0x40,
+       HDMI_PHY_RX_SENSE1 = 0x20,
+       HDMI_PHY_RX_SENSE0 = 0x10,
+       HDMI_PHY_HPD = 0x02,
+       HDMI_PHY_TX_PHY_LOCK = 0x01,
+
+/* PHY_I2CM_SLAVE_ADDR field values */
+       HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2 = 0x69,
+       HDMI_PHY_I2CM_SLAVE_ADDR_HEAC_PHY = 0x49,
+
+/* PHY_I2CM_OPERATION_ADDR field values */
+       HDMI_PHY_I2CM_OPERATION_ADDR_WRITE = 0x10,
+       HDMI_PHY_I2CM_OPERATION_ADDR_READ = 0x1,
+
+/* HDMI_PHY_I2CM_INT_ADDR */
+       HDMI_PHY_I2CM_INT_ADDR_DONE_POL = 0x08,
+       HDMI_PHY_I2CM_INT_ADDR_DONE_MASK = 0x04,
+
+/* HDMI_PHY_I2CM_CTLINT_ADDR */
+       HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL = 0x80,
+       HDMI_PHY_I2CM_CTLINT_ADDR_NAC_MASK = 0x40,
+       HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL = 0x08,
+       HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_MASK = 0x04,
+
+/* AUD_CTS3 field values */
+       HDMI_AUD_CTS3_N_SHIFT_OFFSET = 5,
+       HDMI_AUD_CTS3_N_SHIFT_MASK = 0xe0,
+       HDMI_AUD_CTS3_N_SHIFT_1 = 0,
+       HDMI_AUD_CTS3_N_SHIFT_16 = 0x20,
+       HDMI_AUD_CTS3_N_SHIFT_32 = 0x40,
+       HDMI_AUD_CTS3_N_SHIFT_64 = 0x60,
+       HDMI_AUD_CTS3_N_SHIFT_128 = 0x80,
+       HDMI_AUD_CTS3_N_SHIFT_256 = 0xa0,
+       /* note that the CTS3 MANUAL bit has been removed
+          from our part. Can't set it, will read as 0. */
+       HDMI_AUD_CTS3_CTS_MANUAL = 0x10,
+       HDMI_AUD_CTS3_AUDCTS19_16_MASK = 0x0f,
+
+/* AHB_DMA_CONF0 field values */
+       HDMI_AHB_DMA_CONF0_SW_FIFO_RST_OFFSET = 7,
+       HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK = 0x80,
+       HDMI_AHB_DMA_CONF0_HBR = 0x10,
+       HDMI_AHB_DMA_CONF0_EN_HLOCK_OFFSET = 3,
+       HDMI_AHB_DMA_CONF0_EN_HLOCK_MASK = 0x08,
+       HDMI_AHB_DMA_CONF0_INCR_TYPE_OFFSET = 1,
+       HDMI_AHB_DMA_CONF0_INCR_TYPE_MASK = 0x06,
+       HDMI_AHB_DMA_CONF0_INCR4 = 0x0,
+       HDMI_AHB_DMA_CONF0_INCR8 = 0x2,
+       HDMI_AHB_DMA_CONF0_INCR16 = 0x4,
+       HDMI_AHB_DMA_CONF0_BURST_MODE = 0x1,
+
+/* HDMI_AHB_DMA_START field values */
+       HDMI_AHB_DMA_START_START_OFFSET = 0,
+       HDMI_AHB_DMA_START_START_MASK = 0x01,
+
+/* HDMI_AHB_DMA_STOP field values */
+       HDMI_AHB_DMA_STOP_STOP_OFFSET = 0,
+       HDMI_AHB_DMA_STOP_STOP_MASK = 0x01,
+
+/* AHB_DMA_STAT, AHB_DMA_INT, AHB_DMA_MASK, AHB_DMA_POL field values */
+       HDMI_AHB_DMA_DONE = 0x80,
+       HDMI_AHB_DMA_RETRY_SPLIT = 0x40,
+       HDMI_AHB_DMA_LOSTOWNERSHIP = 0x20,
+       HDMI_AHB_DMA_ERROR = 0x10,
+       HDMI_AHB_DMA_FIFO_THREMPTY = 0x04,
+       HDMI_AHB_DMA_FIFO_FULL = 0x02,
+       HDMI_AHB_DMA_FIFO_EMPTY = 0x01,
+
+/* AHB_DMA_BUFFSTAT, AHB_DMA_BUFFINT,AHB_DMA_BUFFMASK,AHB_DMA_BUFFPOL values */
+       HDMI_AHB_DMA_BUFFSTAT_FULL = 0x02,
+       HDMI_AHB_DMA_BUFFSTAT_EMPTY = 0x01,
+
+/* MC_CLKDIS field values */
+       HDMI_MC_CLKDIS_HDCPCLK_DISABLE = 0x40,
+       HDMI_MC_CLKDIS_CECCLK_DISABLE = 0x20,
+       HDMI_MC_CLKDIS_CSCCLK_DISABLE = 0x10,
+       HDMI_MC_CLKDIS_AUDCLK_DISABLE = 0x8,
+       HDMI_MC_CLKDIS_PREPCLK_DISABLE = 0x4,
+       HDMI_MC_CLKDIS_TMDSCLK_DISABLE = 0x2,
+       HDMI_MC_CLKDIS_PIXELCLK_DISABLE = 0x1,
+
+/* MC_SWRSTZ field values */
+       HDMI_MC_SWRSTZ_TMDSSWRST_REQ = 0x02,
+
+/* MC_FLOWCTRL field values */
+       HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_MASK = 0x1,
+       HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH = 0x1,
+       HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS = 0x0,
+
+/* MC_PHYRSTZ field values */
+       HDMI_MC_PHYRSTZ_ASSERT = 0x0,
+       HDMI_MC_PHYRSTZ_DEASSERT = 0x1,
+
+/* MC_HEACPHY_RST field values */
+       HDMI_MC_HEACPHY_RST_ASSERT = 0x1,
+       HDMI_MC_HEACPHY_RST_DEASSERT = 0x0,
+
+/* CSC_CFG field values */
+       HDMI_CSC_CFG_INTMODE_MASK = 0x30,
+       HDMI_CSC_CFG_INTMODE_OFFSET = 4,
+       HDMI_CSC_CFG_INTMODE_DISABLE = 0x00,
+       HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1 = 0x10,
+       HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA2 = 0x20,
+       HDMI_CSC_CFG_DECMODE_MASK = 0x3,
+       HDMI_CSC_CFG_DECMODE_OFFSET = 0,
+       HDMI_CSC_CFG_DECMODE_DISABLE = 0x0,
+       HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA1 = 0x1,
+       HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA2 = 0x2,
+       HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3 = 0x3,
+
+/* CSC_SCALE field values */
+       HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK = 0xF0,
+       HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP = 0x00,
+       HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP = 0x50,
+       HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP = 0x60,
+       HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP = 0x70,
+       HDMI_CSC_SCALE_CSCSCALE_MASK = 0x03,
+
+/* A_HDCPCFG0 field values */
+       HDMI_A_HDCPCFG0_ELVENA_MASK = 0x80,
+       HDMI_A_HDCPCFG0_ELVENA_ENABLE = 0x80,
+       HDMI_A_HDCPCFG0_ELVENA_DISABLE = 0x00,
+       HDMI_A_HDCPCFG0_I2CFASTMODE_MASK = 0x40,
+       HDMI_A_HDCPCFG0_I2CFASTMODE_ENABLE = 0x40,
+       HDMI_A_HDCPCFG0_I2CFASTMODE_DISABLE = 0x00,
+       HDMI_A_HDCPCFG0_BYPENCRYPTION_MASK = 0x20,
+       HDMI_A_HDCPCFG0_BYPENCRYPTION_ENABLE = 0x20,
+       HDMI_A_HDCPCFG0_BYPENCRYPTION_DISABLE = 0x00,
+       HDMI_A_HDCPCFG0_SYNCRICHECK_MASK = 0x10,
+       HDMI_A_HDCPCFG0_SYNCRICHECK_ENABLE = 0x10,
+       HDMI_A_HDCPCFG0_SYNCRICHECK_DISABLE = 0x00,
+       HDMI_A_HDCPCFG0_AVMUTE_MASK = 0x8,
+       HDMI_A_HDCPCFG0_AVMUTE_ENABLE = 0x8,
+       HDMI_A_HDCPCFG0_AVMUTE_DISABLE = 0x0,
+       HDMI_A_HDCPCFG0_RXDETECT_MASK = 0x4,
+       HDMI_A_HDCPCFG0_RXDETECT_ENABLE = 0x4,
+       HDMI_A_HDCPCFG0_RXDETECT_DISABLE = 0x0,
+       HDMI_A_HDCPCFG0_EN11FEATURE_MASK = 0x2,
+       HDMI_A_HDCPCFG0_EN11FEATURE_ENABLE = 0x2,
+       HDMI_A_HDCPCFG0_EN11FEATURE_DISABLE = 0x0,
+       HDMI_A_HDCPCFG0_HDMIDVI_MASK = 0x1,
+       HDMI_A_HDCPCFG0_HDMIDVI_HDMI = 0x1,
+       HDMI_A_HDCPCFG0_HDMIDVI_DVI = 0x0,
+
+/* A_HDCPCFG1 field values */
+       HDMI_A_HDCPCFG1_DISSHA1CHECK_MASK = 0x8,
+       HDMI_A_HDCPCFG1_DISSHA1CHECK_DISABLE = 0x8,
+       HDMI_A_HDCPCFG1_DISSHA1CHECK_ENABLE = 0x0,
+       HDMI_A_HDCPCFG1_PH2UPSHFTENC_MASK = 0x4,
+       HDMI_A_HDCPCFG1_PH2UPSHFTENC_ENABLE = 0x4,
+       HDMI_A_HDCPCFG1_PH2UPSHFTENC_DISABLE = 0x0,
+       HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK = 0x2,
+       HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE = 0x2,
+       HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_ENABLE = 0x0,
+       HDMI_A_HDCPCFG1_SWRESET_MASK = 0x1,
+       HDMI_A_HDCPCFG1_SWRESET_ASSERT = 0x0,
+
+/* A_VIDPOLCFG field values */
+       HDMI_A_VIDPOLCFG_UNENCRYPTCONF_MASK = 0x60,
+       HDMI_A_VIDPOLCFG_UNENCRYPTCONF_OFFSET = 5,
+       HDMI_A_VIDPOLCFG_DATAENPOL_MASK = 0x10,
+       HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH = 0x10,
+       HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW = 0x0,
+       HDMI_A_VIDPOLCFG_VSYNCPOL_MASK = 0x8,
+       HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_HIGH = 0x8,
+       HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_LOW = 0x0,
+       HDMI_A_VIDPOLCFG_HSYNCPOL_MASK = 0x2,
+       HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2,
+       HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
+};
+#endif /* __IMX_HDMI_H__ */
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
new file mode 100644 (file)
index 0000000..4662e00
--- /dev/null
@@ -0,0 +1,616 @@
+/*
+ * i.MX drm driver - LVDS display bridge
+ *
+ * Copyright (C) 2012 Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <video/of_videomode.h>
+#include <linux/regmap.h>
+#include <linux/videodev2.h>
+
+#include "imx-drm.h"
+
+#define DRIVER_NAME "imx-ldb"
+
+#define LDB_CH0_MODE_EN_TO_DI0         (1 << 0)
+#define LDB_CH0_MODE_EN_TO_DI1         (3 << 0)
+#define LDB_CH0_MODE_EN_MASK           (3 << 0)
+#define LDB_CH1_MODE_EN_TO_DI0         (1 << 2)
+#define LDB_CH1_MODE_EN_TO_DI1         (3 << 2)
+#define LDB_CH1_MODE_EN_MASK           (3 << 2)
+#define LDB_SPLIT_MODE_EN              (1 << 4)
+#define LDB_DATA_WIDTH_CH0_24          (1 << 5)
+#define LDB_BIT_MAP_CH0_JEIDA          (1 << 6)
+#define LDB_DATA_WIDTH_CH1_24          (1 << 7)
+#define LDB_BIT_MAP_CH1_JEIDA          (1 << 8)
+#define LDB_DI0_VS_POL_ACT_LOW         (1 << 9)
+#define LDB_DI1_VS_POL_ACT_LOW         (1 << 10)
+#define LDB_BGREF_RMODE_INT            (1 << 15)
+
+#define con_to_imx_ldb_ch(x) container_of(x, struct imx_ldb_channel, connector)
+#define enc_to_imx_ldb_ch(x) container_of(x, struct imx_ldb_channel, encoder)
+
+struct imx_ldb;
+
+struct imx_ldb_channel {
+       struct imx_ldb *ldb;
+       struct drm_connector connector;
+       struct drm_encoder encoder;
+       struct device_node *child;
+       int chno;
+       void *edid;
+       int edid_len;
+       struct drm_display_mode mode;
+       int mode_valid;
+};
+
+struct bus_mux {
+       int reg;
+       int shift;
+       int mask;
+};
+
+struct imx_ldb {
+       struct regmap *regmap;
+       struct device *dev;
+       struct imx_ldb_channel channel[2];
+       struct clk *clk[2]; /* our own clock */
+       struct clk *clk_sel[4]; /* parent of display clock */
+       struct clk *clk_pll[2]; /* upstream clock we can adjust */
+       u32 ldb_ctrl;
+       const struct bus_mux *lvds_mux;
+};
+
+static enum drm_connector_status imx_ldb_connector_detect(
+               struct drm_connector *connector, bool force)
+{
+       return connector_status_connected;
+}
+
+static int imx_ldb_connector_get_modes(struct drm_connector *connector)
+{
+       struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
+       int num_modes = 0;
+
+       if (imx_ldb_ch->edid) {
+               drm_mode_connector_update_edid_property(connector,
+                                                       imx_ldb_ch->edid);
+               num_modes = drm_add_edid_modes(connector, imx_ldb_ch->edid);
+       }
+
+       if (imx_ldb_ch->mode_valid) {
+               struct drm_display_mode *mode;
+
+               mode = drm_mode_create(connector->dev);
+               if (!mode)
+                       return -EINVAL;
+               drm_mode_copy(mode, &imx_ldb_ch->mode);
+               mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+               drm_mode_probed_add(connector, mode);
+               num_modes++;
+       }
+
+       return num_modes;
+}
+
+static struct drm_encoder *imx_ldb_connector_best_encoder(
+               struct drm_connector *connector)
+{
+       struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
+
+       return &imx_ldb_ch->encoder;
+}
+
+static void imx_ldb_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static bool imx_ldb_encoder_mode_fixup(struct drm_encoder *encoder,
+                          const struct drm_display_mode *mode,
+                          struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno,
+               unsigned long serial_clk, unsigned long di_clk)
+{
+       int ret;
+
+       dev_dbg(ldb->dev, "%s: now: %ld want: %ld\n", __func__,
+                       clk_get_rate(ldb->clk_pll[chno]), serial_clk);
+       clk_set_rate(ldb->clk_pll[chno], serial_clk);
+
+       dev_dbg(ldb->dev, "%s after: %ld\n", __func__,
+                       clk_get_rate(ldb->clk_pll[chno]));
+
+       dev_dbg(ldb->dev, "%s: now: %ld want: %ld\n", __func__,
+                       clk_get_rate(ldb->clk[chno]),
+                       (long int)di_clk);
+       clk_set_rate(ldb->clk[chno], di_clk);
+
+       dev_dbg(ldb->dev, "%s after: %ld\n", __func__,
+                       clk_get_rate(ldb->clk[chno]));
+
+       /* set display clock mux to LDB input clock */
+       ret = clk_set_parent(ldb->clk_sel[mux], ldb->clk[chno]);
+       if (ret)
+               dev_err(ldb->dev,
+                       "unable to set di%d parent clock to ldb_di%d\n", mux,
+                       chno);
+}
+
+static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
+{
+       struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
+       struct imx_ldb *ldb = imx_ldb_ch->ldb;
+       struct drm_display_mode *mode = &encoder->crtc->mode;
+       u32 pixel_fmt;
+       unsigned long serial_clk;
+       unsigned long di_clk = mode->clock * 1000;
+       int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
+
+       if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
+               /* dual channel LVDS mode */
+               serial_clk = 3500UL * mode->clock;
+               imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk);
+               imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk);
+       } else {
+               serial_clk = 7000UL * mode->clock;
+               imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk,
+                               di_clk);
+       }
+
+       switch (imx_ldb_ch->chno) {
+       case 0:
+               pixel_fmt = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH0_24) ?
+                       V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666;
+               break;
+       case 1:
+               pixel_fmt = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH1_24) ?
+                       V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666;
+               break;
+       default:
+               dev_err(ldb->dev, "unable to config di%d panel format\n",
+                       imx_ldb_ch->chno);
+               pixel_fmt = V4L2_PIX_FMT_RGB24;
+       }
+
+       imx_drm_panel_format(encoder, pixel_fmt);
+}
+
+static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
+{
+       struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
+       struct imx_ldb *ldb = imx_ldb_ch->ldb;
+       int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
+       int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
+
+       if (dual) {
+               clk_prepare_enable(ldb->clk[0]);
+               clk_prepare_enable(ldb->clk[1]);
+       }
+
+       if (imx_ldb_ch == &ldb->channel[0] || dual) {
+               ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
+               if (mux == 0 || ldb->lvds_mux)
+                       ldb->ldb_ctrl |= LDB_CH0_MODE_EN_TO_DI0;
+               else if (mux == 1)
+                       ldb->ldb_ctrl |= LDB_CH0_MODE_EN_TO_DI1;
+       }
+       if (imx_ldb_ch == &ldb->channel[1] || dual) {
+               ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK;
+               if (mux == 1 || ldb->lvds_mux)
+                       ldb->ldb_ctrl |= LDB_CH1_MODE_EN_TO_DI1;
+               else if (mux == 0)
+                       ldb->ldb_ctrl |= LDB_CH1_MODE_EN_TO_DI0;
+       }
+
+       if (ldb->lvds_mux) {
+               const struct bus_mux *lvds_mux = NULL;
+
+               if (imx_ldb_ch == &ldb->channel[0])
+                       lvds_mux = &ldb->lvds_mux[0];
+               else if (imx_ldb_ch == &ldb->channel[1])
+                       lvds_mux = &ldb->lvds_mux[1];
+
+               regmap_update_bits(ldb->regmap, lvds_mux->reg, lvds_mux->mask,
+                                  mux << lvds_mux->shift);
+       }
+
+       regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
+}
+
+static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
+                        struct drm_display_mode *mode,
+                        struct drm_display_mode *adjusted_mode)
+{
+       struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
+       struct imx_ldb *ldb = imx_ldb_ch->ldb;
+       int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
+
+       if (mode->clock > 170000) {
+               dev_warn(ldb->dev,
+                        "%s: mode exceeds 170 MHz pixel clock\n", __func__);
+       }
+       if (mode->clock > 85000 && !dual) {
+               dev_warn(ldb->dev,
+                        "%s: mode exceeds 85 MHz pixel clock\n", __func__);
+       }
+
+       /* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */
+       if (imx_ldb_ch == &ldb->channel[0]) {
+               if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+                       ldb->ldb_ctrl |= LDB_DI0_VS_POL_ACT_LOW;
+               else if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+                       ldb->ldb_ctrl &= ~LDB_DI0_VS_POL_ACT_LOW;
+       }
+       if (imx_ldb_ch == &ldb->channel[1]) {
+               if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+                       ldb->ldb_ctrl |= LDB_DI1_VS_POL_ACT_LOW;
+               else if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+                       ldb->ldb_ctrl &= ~LDB_DI1_VS_POL_ACT_LOW;
+       }
+}
+
+static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
+{
+       struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
+       struct imx_ldb *ldb = imx_ldb_ch->ldb;
+
+       /*
+        * imx_ldb_encoder_disable is called by
+        * drm_helper_disable_unused_functions without
+        * the encoder being enabled before.
+        */
+       if (imx_ldb_ch == &ldb->channel[0] &&
+           (ldb->ldb_ctrl & LDB_CH0_MODE_EN_MASK) == 0)
+               return;
+       else if (imx_ldb_ch == &ldb->channel[1] &&
+                (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0)
+               return;
+
+       if (imx_ldb_ch == &ldb->channel[0])
+               ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
+       else if (imx_ldb_ch == &ldb->channel[1])
+               ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK;
+
+       regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
+
+       if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
+               clk_disable_unprepare(ldb->clk[0]);
+               clk_disable_unprepare(ldb->clk[1]);
+       }
+}
+
+static struct drm_connector_funcs imx_ldb_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .detect = imx_ldb_connector_detect,
+       .destroy = imx_drm_connector_destroy,
+};
+
+static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
+       .get_modes = imx_ldb_connector_get_modes,
+       .best_encoder = imx_ldb_connector_best_encoder,
+};
+
+static struct drm_encoder_funcs imx_ldb_encoder_funcs = {
+       .destroy = imx_drm_encoder_destroy,
+};
+
+static struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = {
+       .dpms = imx_ldb_encoder_dpms,
+       .mode_fixup = imx_ldb_encoder_mode_fixup,
+       .prepare = imx_ldb_encoder_prepare,
+       .commit = imx_ldb_encoder_commit,
+       .mode_set = imx_ldb_encoder_mode_set,
+       .disable = imx_ldb_encoder_disable,
+};
+
+static int imx_ldb_get_clk(struct imx_ldb *ldb, int chno)
+{
+       char clkname[16];
+
+       snprintf(clkname, sizeof(clkname), "di%d", chno);
+       ldb->clk[chno] = devm_clk_get(ldb->dev, clkname);
+       if (IS_ERR(ldb->clk[chno]))
+               return PTR_ERR(ldb->clk[chno]);
+
+       snprintf(clkname, sizeof(clkname), "di%d_pll", chno);
+       ldb->clk_pll[chno] = devm_clk_get(ldb->dev, clkname);
+
+       return PTR_ERR_OR_ZERO(ldb->clk_pll[chno]);
+}
+
+static int imx_ldb_register(struct drm_device *drm,
+       struct imx_ldb_channel *imx_ldb_ch)
+{
+       struct imx_ldb *ldb = imx_ldb_ch->ldb;
+       int ret;
+
+       ret = imx_drm_encoder_parse_of(drm, &imx_ldb_ch->encoder,
+                                      imx_ldb_ch->child);
+       if (ret)
+               return ret;
+
+       ret = imx_ldb_get_clk(ldb, imx_ldb_ch->chno);
+       if (ret)
+               return ret;
+
+       if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
+               ret = imx_ldb_get_clk(ldb, 1);
+               if (ret)
+                       return ret;
+       }
+
+       drm_encoder_helper_add(&imx_ldb_ch->encoder,
+                       &imx_ldb_encoder_helper_funcs);
+       drm_encoder_init(drm, &imx_ldb_ch->encoder, &imx_ldb_encoder_funcs,
+                        DRM_MODE_ENCODER_LVDS);
+
+       drm_connector_helper_add(&imx_ldb_ch->connector,
+                       &imx_ldb_connector_helper_funcs);
+       drm_connector_init(drm, &imx_ldb_ch->connector,
+                          &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
+
+       drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
+                       &imx_ldb_ch->encoder);
+
+       return 0;
+}
+
+enum {
+       LVDS_BIT_MAP_SPWG,
+       LVDS_BIT_MAP_JEIDA
+};
+
+static const char * const imx_ldb_bit_mappings[] = {
+       [LVDS_BIT_MAP_SPWG]  = "spwg",
+       [LVDS_BIT_MAP_JEIDA] = "jeida",
+};
+
+static const int of_get_data_mapping(struct device_node *np)
+{
+       const char *bm;
+       int ret, i;
+
+       ret = of_property_read_string(np, "fsl,data-mapping", &bm);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++)
+               if (!strcasecmp(bm, imx_ldb_bit_mappings[i]))
+                       return i;
+
+       return -EINVAL;
+}
+
+static struct bus_mux imx6q_lvds_mux[2] = {
+       {
+               .reg = IOMUXC_GPR3,
+               .shift = 6,
+               .mask = IMX6Q_GPR3_LVDS0_MUX_CTL_MASK,
+       }, {
+               .reg = IOMUXC_GPR3,
+               .shift = 8,
+               .mask = IMX6Q_GPR3_LVDS1_MUX_CTL_MASK,
+       }
+};
+
+/*
+ * For a device declaring compatible = "fsl,imx6q-ldb", "fsl,imx53-ldb",
+ * of_match_device will walk through this list and take the first entry
+ * matching any of its compatible values. Therefore, the more generic
+ * entries (in this case fsl,imx53-ldb) need to be ordered last.
+ */
+static const struct of_device_id imx_ldb_dt_ids[] = {
+       { .compatible = "fsl,imx6q-ldb", .data = imx6q_lvds_mux, },
+       { .compatible = "fsl,imx53-ldb", .data = NULL, },
+       { }
+};
+MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
+
+static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
+{
+       struct drm_device *drm = data;
+       struct device_node *np = dev->of_node;
+       const struct of_device_id *of_id =
+                       of_match_device(imx_ldb_dt_ids, dev);
+       struct device_node *child;
+       const u8 *edidp;
+       struct imx_ldb *imx_ldb;
+       int datawidth;
+       int mapping;
+       int dual;
+       int ret;
+       int i;
+
+       imx_ldb = devm_kzalloc(dev, sizeof(*imx_ldb), GFP_KERNEL);
+       if (!imx_ldb)
+               return -ENOMEM;
+
+       imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
+       if (IS_ERR(imx_ldb->regmap)) {
+               dev_err(dev, "failed to get parent regmap\n");
+               return PTR_ERR(imx_ldb->regmap);
+       }
+
+       imx_ldb->dev = dev;
+
+       if (of_id)
+               imx_ldb->lvds_mux = of_id->data;
+
+       dual = of_property_read_bool(np, "fsl,dual-channel");
+       if (dual)
+               imx_ldb->ldb_ctrl |= LDB_SPLIT_MODE_EN;
+
+       /*
+        * There are three different possible clock mux configurations:
+        * i.MX53:  ipu1_di0_sel, ipu1_di1_sel
+        * i.MX6q:  ipu1_di0_sel, ipu1_di1_sel, ipu2_di0_sel, ipu2_di1_sel
+        * i.MX6dl: ipu1_di0_sel, ipu1_di1_sel, lcdif_sel
+        * Map them all to di0_sel...di3_sel.
+        */
+       for (i = 0; i < 4; i++) {
+               char clkname[16];
+
+               sprintf(clkname, "di%d_sel", i);
+               imx_ldb->clk_sel[i] = devm_clk_get(imx_ldb->dev, clkname);
+               if (IS_ERR(imx_ldb->clk_sel[i])) {
+                       ret = PTR_ERR(imx_ldb->clk_sel[i]);
+                       imx_ldb->clk_sel[i] = NULL;
+                       break;
+               }
+       }
+       if (i == 0)
+               return ret;
+
+       for_each_child_of_node(np, child) {
+               struct imx_ldb_channel *channel;
+
+               ret = of_property_read_u32(child, "reg", &i);
+               if (ret || i < 0 || i > 1)
+                       return -EINVAL;
+
+               if (dual && i > 0) {
+                       dev_warn(dev, "dual-channel mode, ignoring second output\n");
+                       continue;
+               }
+
+               if (!of_device_is_available(child))
+                       continue;
+
+               channel = &imx_ldb->channel[i];
+               channel->ldb = imx_ldb;
+               channel->chno = i;
+               channel->child = child;
+
+               edidp = of_get_property(child, "edid", &channel->edid_len);
+               if (edidp) {
+                       channel->edid = kmemdup(edidp, channel->edid_len,
+                                               GFP_KERNEL);
+               } else {
+                       ret = of_get_drm_display_mode(child, &channel->mode, 0);
+                       if (!ret)
+                               channel->mode_valid = 1;
+               }
+
+               ret = of_property_read_u32(child, "fsl,data-width", &datawidth);
+               if (ret)
+                       datawidth = 0;
+               else if (datawidth != 18 && datawidth != 24)
+                       return -EINVAL;
+
+               mapping = of_get_data_mapping(child);
+               switch (mapping) {
+               case LVDS_BIT_MAP_SPWG:
+                       if (datawidth == 24) {
+                               if (i == 0 || dual)
+                                       imx_ldb->ldb_ctrl |=
+                                               LDB_DATA_WIDTH_CH0_24;
+                               if (i == 1 || dual)
+                                       imx_ldb->ldb_ctrl |=
+                                               LDB_DATA_WIDTH_CH1_24;
+                       }
+                       break;
+               case LVDS_BIT_MAP_JEIDA:
+                       if (datawidth == 18) {
+                               dev_err(dev, "JEIDA standard only supported in 24 bit\n");
+                               return -EINVAL;
+                       }
+                       if (i == 0 || dual)
+                               imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 |
+                                       LDB_BIT_MAP_CH0_JEIDA;
+                       if (i == 1 || dual)
+                               imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 |
+                                       LDB_BIT_MAP_CH1_JEIDA;
+                       break;
+               default:
+                       dev_err(dev, "data mapping not specified or invalid\n");
+                       return -EINVAL;
+               }
+
+               ret = imx_ldb_register(drm, channel);
+               if (ret)
+                       return ret;
+       }
+
+       dev_set_drvdata(dev, imx_ldb);
+
+       return 0;
+}
+
+static void imx_ldb_unbind(struct device *dev, struct device *master,
+       void *data)
+{
+       struct imx_ldb *imx_ldb = dev_get_drvdata(dev);
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               struct imx_ldb_channel *channel = &imx_ldb->channel[i];
+
+               if (!channel->connector.funcs)
+                       continue;
+
+               channel->connector.funcs->destroy(&channel->connector);
+               channel->encoder.funcs->destroy(&channel->encoder);
+       }
+}
+
+static const struct component_ops imx_ldb_ops = {
+       .bind   = imx_ldb_bind,
+       .unbind = imx_ldb_unbind,
+};
+
+static int imx_ldb_probe(struct platform_device *pdev)
+{
+       return component_add(&pdev->dev, &imx_ldb_ops);
+}
+
+static int imx_ldb_remove(struct platform_device *pdev)
+{
+       component_del(&pdev->dev, &imx_ldb_ops);
+       return 0;
+}
+
+static struct platform_driver imx_ldb_driver = {
+       .probe          = imx_ldb_probe,
+       .remove         = imx_ldb_remove,
+       .driver         = {
+               .of_match_table = imx_ldb_dt_ids,
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+module_platform_driver(imx_ldb_driver);
+
+MODULE_DESCRIPTION("i.MX LVDS driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c
new file mode 100644 (file)
index 0000000..42c651b
--- /dev/null
@@ -0,0 +1,736 @@
+/*
+ * i.MX drm driver - Television Encoder (TVEv2)
+ *
+ * Copyright (C) 2013 Philipp Zabel, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <video/imx-ipu-v3.h>
+
+#include "imx-drm.h"
+
+#define TVE_COM_CONF_REG       0x00
+#define TVE_TVDAC0_CONT_REG    0x28
+#define TVE_TVDAC1_CONT_REG    0x2c
+#define TVE_TVDAC2_CONT_REG    0x30
+#define TVE_CD_CONT_REG                0x34
+#define TVE_INT_CONT_REG       0x64
+#define TVE_STAT_REG           0x68
+#define TVE_TST_MODE_REG       0x6c
+#define TVE_MV_CONT_REG                0xdc
+
+/* TVE_COM_CONF_REG */
+#define TVE_SYNC_CH_2_EN       BIT(22)
+#define TVE_SYNC_CH_1_EN       BIT(21)
+#define TVE_SYNC_CH_0_EN       BIT(20)
+#define TVE_TV_OUT_MODE_MASK   (0x7 << 12)
+#define TVE_TV_OUT_DISABLE     (0x0 << 12)
+#define TVE_TV_OUT_CVBS_0      (0x1 << 12)
+#define TVE_TV_OUT_CVBS_2      (0x2 << 12)
+#define TVE_TV_OUT_CVBS_0_2    (0x3 << 12)
+#define TVE_TV_OUT_SVIDEO_0_1  (0x4 << 12)
+#define TVE_TV_OUT_SVIDEO_0_1_CVBS2_2  (0x5 << 12)
+#define TVE_TV_OUT_YPBPR       (0x6 << 12)
+#define TVE_TV_OUT_RGB         (0x7 << 12)
+#define TVE_TV_STAND_MASK      (0xf << 8)
+#define TVE_TV_STAND_HD_1080P30        (0xc << 8)
+#define TVE_P2I_CONV_EN                BIT(7)
+#define TVE_INP_VIDEO_FORM     BIT(6)
+#define TVE_INP_YCBCR_422      (0x0 << 6)
+#define TVE_INP_YCBCR_444      (0x1 << 6)
+#define TVE_DATA_SOURCE_MASK   (0x3 << 4)
+#define TVE_DATA_SOURCE_BUS1   (0x0 << 4)
+#define TVE_DATA_SOURCE_BUS2   (0x1 << 4)
+#define TVE_DATA_SOURCE_EXT    (0x2 << 4)
+#define TVE_DATA_SOURCE_TESTGEN        (0x3 << 4)
+#define TVE_IPU_CLK_EN_OFS     3
+#define TVE_IPU_CLK_EN         BIT(3)
+#define TVE_DAC_SAMP_RATE_OFS  1
+#define TVE_DAC_SAMP_RATE_WIDTH        2
+#define TVE_DAC_SAMP_RATE_MASK (0x3 << 1)
+#define TVE_DAC_FULL_RATE      (0x0 << 1)
+#define TVE_DAC_DIV2_RATE      (0x1 << 1)
+#define TVE_DAC_DIV4_RATE      (0x2 << 1)
+#define TVE_EN                 BIT(0)
+
+/* TVE_TVDACx_CONT_REG */
+#define TVE_TVDAC_GAIN_MASK    (0x3f << 0)
+
+/* TVE_CD_CONT_REG */
+#define TVE_CD_CH_2_SM_EN      BIT(22)
+#define TVE_CD_CH_1_SM_EN      BIT(21)
+#define TVE_CD_CH_0_SM_EN      BIT(20)
+#define TVE_CD_CH_2_LM_EN      BIT(18)
+#define TVE_CD_CH_1_LM_EN      BIT(17)
+#define TVE_CD_CH_0_LM_EN      BIT(16)
+#define TVE_CD_CH_2_REF_LVL    BIT(10)
+#define TVE_CD_CH_1_REF_LVL    BIT(9)
+#define TVE_CD_CH_0_REF_LVL    BIT(8)
+#define TVE_CD_EN              BIT(0)
+
+/* TVE_INT_CONT_REG */
+#define TVE_FRAME_END_IEN      BIT(13)
+#define TVE_CD_MON_END_IEN     BIT(2)
+#define TVE_CD_SM_IEN          BIT(1)
+#define TVE_CD_LM_IEN          BIT(0)
+
+/* TVE_TST_MODE_REG */
+#define TVE_TVDAC_TEST_MODE_MASK       (0x7 << 0)
+
+#define con_to_tve(x) container_of(x, struct imx_tve, connector)
+#define enc_to_tve(x) container_of(x, struct imx_tve, encoder)
+
+enum {
+       TVE_MODE_TVOUT,
+       TVE_MODE_VGA,
+};
+
+struct imx_tve {
+       struct drm_connector connector;
+       struct drm_encoder encoder;
+       struct device *dev;
+       spinlock_t lock;        /* register lock */
+       bool enabled;
+       int mode;
+
+       struct regmap *regmap;
+       struct regulator *dac_reg;
+       struct i2c_adapter *ddc;
+       struct clk *clk;
+       struct clk *di_sel_clk;
+       struct clk_hw clk_hw_di;
+       struct clk *di_clk;
+       int vsync_pin;
+       int hsync_pin;
+};
+
+static void tve_lock(void *__tve)
+__acquires(&tve->lock)
+{
+       struct imx_tve *tve = __tve;
+
+       spin_lock(&tve->lock);
+}
+
+static void tve_unlock(void *__tve)
+__releases(&tve->lock)
+{
+       struct imx_tve *tve = __tve;
+
+       spin_unlock(&tve->lock);
+}
+
+static void tve_enable(struct imx_tve *tve)
+{
+       int ret;
+
+       if (!tve->enabled) {
+               tve->enabled = true;
+               clk_prepare_enable(tve->clk);
+               ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG,
+                                        TVE_IPU_CLK_EN | TVE_EN,
+                                        TVE_IPU_CLK_EN | TVE_EN);
+       }
+
+       /* clear interrupt status register */
+       regmap_write(tve->regmap, TVE_STAT_REG, 0xffffffff);
+
+       /* cable detection irq disabled in VGA mode, enabled in TVOUT mode */
+       if (tve->mode == TVE_MODE_VGA)
+               regmap_write(tve->regmap, TVE_INT_CONT_REG, 0);
+       else
+               regmap_write(tve->regmap, TVE_INT_CONT_REG,
+                            TVE_CD_SM_IEN |
+                            TVE_CD_LM_IEN |
+                            TVE_CD_MON_END_IEN);
+}
+
+static void tve_disable(struct imx_tve *tve)
+{
+       int ret;
+
+       if (tve->enabled) {
+               tve->enabled = false;
+               ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG,
+                                        TVE_IPU_CLK_EN | TVE_EN, 0);
+               clk_disable_unprepare(tve->clk);
+       }
+}
+
+static int tve_setup_tvout(struct imx_tve *tve)
+{
+       return -ENOTSUPP;
+}
+
+static int tve_setup_vga(struct imx_tve *tve)
+{
+       unsigned int mask;
+       unsigned int val;
+       int ret;
+
+       /* set gain to (1 + 10/128) to provide 0.7V peak-to-peak amplitude */
+       ret = regmap_update_bits(tve->regmap, TVE_TVDAC0_CONT_REG,
+                                TVE_TVDAC_GAIN_MASK, 0x0a);
+       ret = regmap_update_bits(tve->regmap, TVE_TVDAC1_CONT_REG,
+                                TVE_TVDAC_GAIN_MASK, 0x0a);
+       ret = regmap_update_bits(tve->regmap, TVE_TVDAC2_CONT_REG,
+                                TVE_TVDAC_GAIN_MASK, 0x0a);
+
+       /* set configuration register */
+       mask = TVE_DATA_SOURCE_MASK | TVE_INP_VIDEO_FORM;
+       val  = TVE_DATA_SOURCE_BUS2 | TVE_INP_YCBCR_444;
+       mask |= TVE_TV_STAND_MASK       | TVE_P2I_CONV_EN;
+       val  |= TVE_TV_STAND_HD_1080P30 | 0;
+       mask |= TVE_TV_OUT_MODE_MASK | TVE_SYNC_CH_0_EN;
+       val  |= TVE_TV_OUT_RGB       | TVE_SYNC_CH_0_EN;
+       ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, mask, val);
+       if (ret < 0) {
+               dev_err(tve->dev, "failed to set configuration: %d\n", ret);
+               return ret;
+       }
+
+       /* set test mode (as documented) */
+       ret = regmap_update_bits(tve->regmap, TVE_TST_MODE_REG,
+                                TVE_TVDAC_TEST_MODE_MASK, 1);
+
+       return 0;
+}
+
+static enum drm_connector_status imx_tve_connector_detect(
+                               struct drm_connector *connector, bool force)
+{
+       return connector_status_connected;
+}
+
+static int imx_tve_connector_get_modes(struct drm_connector *connector)
+{
+       struct imx_tve *tve = con_to_tve(connector);
+       struct edid *edid;
+       int ret = 0;
+
+       if (!tve->ddc)
+               return 0;
+
+       edid = drm_get_edid(connector, tve->ddc);
+       if (edid) {
+               drm_mode_connector_update_edid_property(connector, edid);
+               ret = drm_add_edid_modes(connector, edid);
+               kfree(edid);
+       }
+
+       return ret;
+}
+
+static int imx_tve_connector_mode_valid(struct drm_connector *connector,
+                                       struct drm_display_mode *mode)
+{
+       struct imx_tve *tve = con_to_tve(connector);
+       unsigned long rate;
+
+       /* pixel clock with 2x oversampling */
+       rate = clk_round_rate(tve->clk, 2000UL * mode->clock) / 2000;
+       if (rate == mode->clock)
+               return MODE_OK;
+
+       /* pixel clock without oversampling */
+       rate = clk_round_rate(tve->clk, 1000UL * mode->clock) / 1000;
+       if (rate == mode->clock)
+               return MODE_OK;
+
+       dev_warn(tve->dev, "ignoring mode %dx%d\n",
+                mode->hdisplay, mode->vdisplay);
+
+       return MODE_BAD;
+}
+
+static struct drm_encoder *imx_tve_connector_best_encoder(
+               struct drm_connector *connector)
+{
+       struct imx_tve *tve = con_to_tve(connector);
+
+       return &tve->encoder;
+}
+
+static void imx_tve_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct imx_tve *tve = enc_to_tve(encoder);
+       int ret;
+
+       ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG,
+                                TVE_TV_OUT_MODE_MASK, TVE_TV_OUT_DISABLE);
+       if (ret < 0)
+               dev_err(tve->dev, "failed to disable TVOUT: %d\n", ret);
+}
+
+static bool imx_tve_encoder_mode_fixup(struct drm_encoder *encoder,
+                                      const struct drm_display_mode *mode,
+                                      struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void imx_tve_encoder_prepare(struct drm_encoder *encoder)
+{
+       struct imx_tve *tve = enc_to_tve(encoder);
+
+       tve_disable(tve);
+
+       switch (tve->mode) {
+       case TVE_MODE_VGA:
+               imx_drm_panel_format_pins(encoder, IPU_PIX_FMT_GBR24,
+                               tve->hsync_pin, tve->vsync_pin);
+               break;
+       case TVE_MODE_TVOUT:
+               imx_drm_panel_format(encoder, V4L2_PIX_FMT_YUV444);
+               break;
+       }
+}
+
+static void imx_tve_encoder_mode_set(struct drm_encoder *encoder,
+                                    struct drm_display_mode *mode,
+                                    struct drm_display_mode *adjusted_mode)
+{
+       struct imx_tve *tve = enc_to_tve(encoder);
+       unsigned long rounded_rate;
+       unsigned long rate;
+       int div = 1;
+       int ret;
+
+       /*
+        * FIXME
+        * we should try 4k * mode->clock first,
+        * and enable 4x oversampling for lower resolutions
+        */
+       rate = 2000UL * mode->clock;
+       clk_set_rate(tve->clk, rate);
+       rounded_rate = clk_get_rate(tve->clk);
+       if (rounded_rate >= rate)
+               div = 2;
+       clk_set_rate(tve->di_clk, rounded_rate / div);
+
+       ret = clk_set_parent(tve->di_sel_clk, tve->di_clk);
+       if (ret < 0) {
+               dev_err(tve->dev, "failed to set di_sel parent to tve_di: %d\n",
+                       ret);
+       }
+
+       if (tve->mode == TVE_MODE_VGA)
+               tve_setup_vga(tve);
+       else
+               tve_setup_tvout(tve);
+}
+
+static void imx_tve_encoder_commit(struct drm_encoder *encoder)
+{
+       struct imx_tve *tve = enc_to_tve(encoder);
+
+       tve_enable(tve);
+}
+
+static void imx_tve_encoder_disable(struct drm_encoder *encoder)
+{
+       struct imx_tve *tve = enc_to_tve(encoder);
+
+       tve_disable(tve);
+}
+
+static struct drm_connector_funcs imx_tve_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .detect = imx_tve_connector_detect,
+       .destroy = imx_drm_connector_destroy,
+};
+
+static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
+       .get_modes = imx_tve_connector_get_modes,
+       .best_encoder = imx_tve_connector_best_encoder,
+       .mode_valid = imx_tve_connector_mode_valid,
+};
+
+static struct drm_encoder_funcs imx_tve_encoder_funcs = {
+       .destroy = imx_drm_encoder_destroy,
+};
+
+static struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = {
+       .dpms = imx_tve_encoder_dpms,
+       .mode_fixup = imx_tve_encoder_mode_fixup,
+       .prepare = imx_tve_encoder_prepare,
+       .mode_set = imx_tve_encoder_mode_set,
+       .commit = imx_tve_encoder_commit,
+       .disable = imx_tve_encoder_disable,
+};
+
+static irqreturn_t imx_tve_irq_handler(int irq, void *data)
+{
+       struct imx_tve *tve = data;
+       unsigned int val;
+
+       regmap_read(tve->regmap, TVE_STAT_REG, &val);
+
+       /* clear interrupt status register */
+       regmap_write(tve->regmap, TVE_STAT_REG, 0xffffffff);
+
+       return IRQ_HANDLED;
+}
+
+static unsigned long clk_tve_di_recalc_rate(struct clk_hw *hw,
+                                           unsigned long parent_rate)
+{
+       struct imx_tve *tve = container_of(hw, struct imx_tve, clk_hw_di);
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(tve->regmap, TVE_COM_CONF_REG, &val);
+       if (ret < 0)
+               return 0;
+
+       switch (val & TVE_DAC_SAMP_RATE_MASK) {
+       case TVE_DAC_DIV4_RATE:
+               return parent_rate / 4;
+       case TVE_DAC_DIV2_RATE:
+               return parent_rate / 2;
+       case TVE_DAC_FULL_RATE:
+       default:
+               return parent_rate;
+       }
+
+       return 0;
+}
+
+static long clk_tve_di_round_rate(struct clk_hw *hw, unsigned long rate,
+                                 unsigned long *prate)
+{
+       unsigned long div;
+
+       div = *prate / rate;
+       if (div >= 4)
+               return *prate / 4;
+       else if (div >= 2)
+               return *prate / 2;
+       return *prate;
+}
+
+static int clk_tve_di_set_rate(struct clk_hw *hw, unsigned long rate,
+                              unsigned long parent_rate)
+{
+       struct imx_tve *tve = container_of(hw, struct imx_tve, clk_hw_di);
+       unsigned long div;
+       u32 val;
+       int ret;
+
+       div = parent_rate / rate;
+       if (div >= 4)
+               val = TVE_DAC_DIV4_RATE;
+       else if (div >= 2)
+               val = TVE_DAC_DIV2_RATE;
+       else
+               val = TVE_DAC_FULL_RATE;
+
+       ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG,
+                                TVE_DAC_SAMP_RATE_MASK, val);
+
+       if (ret < 0) {
+               dev_err(tve->dev, "failed to set divider: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct clk_ops clk_tve_di_ops = {
+       .round_rate = clk_tve_di_round_rate,
+       .set_rate = clk_tve_di_set_rate,
+       .recalc_rate = clk_tve_di_recalc_rate,
+};
+
+static int tve_clk_init(struct imx_tve *tve, void __iomem *base)
+{
+       const char *tve_di_parent[1];
+       struct clk_init_data init = {
+               .name = "tve_di",
+               .ops = &clk_tve_di_ops,
+               .num_parents = 1,
+               .flags = 0,
+       };
+
+       tve_di_parent[0] = __clk_get_name(tve->clk);
+       init.parent_names = (const char **)&tve_di_parent;
+
+       tve->clk_hw_di.init = &init;
+       tve->di_clk = clk_register(tve->dev, &tve->clk_hw_di);
+       if (IS_ERR(tve->di_clk)) {
+               dev_err(tve->dev, "failed to register TVE output clock: %ld\n",
+                       PTR_ERR(tve->di_clk));
+               return PTR_ERR(tve->di_clk);
+       }
+
+       return 0;
+}
+
+static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve)
+{
+       int encoder_type;
+       int ret;
+
+       encoder_type = tve->mode == TVE_MODE_VGA ?
+                               DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC;
+
+       ret = imx_drm_encoder_parse_of(drm, &tve->encoder,
+                                      tve->dev->of_node);
+       if (ret)
+               return ret;
+
+       drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs);
+       drm_encoder_init(drm, &tve->encoder, &imx_tve_encoder_funcs,
+                        encoder_type);
+
+       drm_connector_helper_add(&tve->connector,
+                       &imx_tve_connector_helper_funcs);
+       drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs,
+                          DRM_MODE_CONNECTOR_VGA);
+
+       drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder);
+
+       return 0;
+}
+
+static bool imx_tve_readable_reg(struct device *dev, unsigned int reg)
+{
+       return (reg % 4 == 0) && (reg <= 0xdc);
+}
+
+static struct regmap_config tve_regmap_config = {
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+
+       .readable_reg = imx_tve_readable_reg,
+
+       .lock = tve_lock,
+       .unlock = tve_unlock,
+
+       .max_register = 0xdc,
+};
+
+static const char * const imx_tve_modes[] = {
+       [TVE_MODE_TVOUT]  = "tvout",
+       [TVE_MODE_VGA] = "vga",
+};
+
+static const int of_get_tve_mode(struct device_node *np)
+{
+       const char *bm;
+       int ret, i;
+
+       ret = of_property_read_string(np, "fsl,tve-mode", &bm);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < ARRAY_SIZE(imx_tve_modes); i++)
+               if (!strcasecmp(bm, imx_tve_modes[i]))
+                       return i;
+
+       return -EINVAL;
+}
+
+static int imx_tve_bind(struct device *dev, struct device *master, void *data)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct drm_device *drm = data;
+       struct device_node *np = dev->of_node;
+       struct device_node *ddc_node;
+       struct imx_tve *tve;
+       struct resource *res;
+       void __iomem *base;
+       unsigned int val;
+       int irq;
+       int ret;
+
+       tve = devm_kzalloc(dev, sizeof(*tve), GFP_KERNEL);
+       if (!tve)
+               return -ENOMEM;
+
+       tve->dev = dev;
+       spin_lock_init(&tve->lock);
+
+       ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
+       if (ddc_node) {
+               tve->ddc = of_find_i2c_adapter_by_node(ddc_node);
+               of_node_put(ddc_node);
+       }
+
+       tve->mode = of_get_tve_mode(np);
+       if (tve->mode != TVE_MODE_VGA) {
+               dev_err(dev, "only VGA mode supported, currently\n");
+               return -EINVAL;
+       }
+
+       if (tve->mode == TVE_MODE_VGA) {
+               ret = of_property_read_u32(np, "fsl,hsync-pin",
+                                          &tve->hsync_pin);
+
+               if (ret < 0) {
+                       dev_err(dev, "failed to get vsync pin\n");
+                       return ret;
+               }
+
+               ret |= of_property_read_u32(np, "fsl,vsync-pin",
+                                           &tve->vsync_pin);
+
+               if (ret < 0) {
+                       dev_err(dev, "failed to get vsync pin\n");
+                       return ret;
+               }
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       tve_regmap_config.lock_arg = tve;
+       tve->regmap = devm_regmap_init_mmio_clk(dev, "tve", base,
+                                               &tve_regmap_config);
+       if (IS_ERR(tve->regmap)) {
+               dev_err(dev, "failed to init regmap: %ld\n",
+                       PTR_ERR(tve->regmap));
+               return PTR_ERR(tve->regmap);
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(dev, "failed to get irq\n");
+               return irq;
+       }
+
+       ret = devm_request_threaded_irq(dev, irq, NULL,
+                                       imx_tve_irq_handler, IRQF_ONESHOT,
+                                       "imx-tve", tve);
+       if (ret < 0) {
+               dev_err(dev, "failed to request irq: %d\n", ret);
+               return ret;
+       }
+
+       tve->dac_reg = devm_regulator_get(dev, "dac");
+       if (!IS_ERR(tve->dac_reg)) {
+               regulator_set_voltage(tve->dac_reg, 2750000, 2750000);
+               ret = regulator_enable(tve->dac_reg);
+               if (ret)
+                       return ret;
+       }
+
+       tve->clk = devm_clk_get(dev, "tve");
+       if (IS_ERR(tve->clk)) {
+               dev_err(dev, "failed to get high speed tve clock: %ld\n",
+                       PTR_ERR(tve->clk));
+               return PTR_ERR(tve->clk);
+       }
+
+       /* this is the IPU DI clock input selector, can be parented to tve_di */
+       tve->di_sel_clk = devm_clk_get(dev, "di_sel");
+       if (IS_ERR(tve->di_sel_clk)) {
+               dev_err(dev, "failed to get ipu di mux clock: %ld\n",
+                       PTR_ERR(tve->di_sel_clk));
+               return PTR_ERR(tve->di_sel_clk);
+       }
+
+       ret = tve_clk_init(tve, base);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_read(tve->regmap, TVE_COM_CONF_REG, &val);
+       if (ret < 0) {
+               dev_err(dev, "failed to read configuration register: %d\n", ret);
+               return ret;
+       }
+       if (val != 0x00100000) {
+               dev_err(dev, "configuration register default value indicates this is not a TVEv2\n");
+               return -ENODEV;
+       }
+
+       /* disable cable detection for VGA mode */
+       ret = regmap_write(tve->regmap, TVE_CD_CONT_REG, 0);
+
+       ret = imx_tve_register(drm, tve);
+       if (ret)
+               return ret;
+
+       dev_set_drvdata(dev, tve);
+
+       return 0;
+}
+
+static void imx_tve_unbind(struct device *dev, struct device *master,
+       void *data)
+{
+       struct imx_tve *tve = dev_get_drvdata(dev);
+
+       tve->connector.funcs->destroy(&tve->connector);
+       tve->encoder.funcs->destroy(&tve->encoder);
+
+       if (!IS_ERR(tve->dac_reg))
+               regulator_disable(tve->dac_reg);
+}
+
+static const struct component_ops imx_tve_ops = {
+       .bind   = imx_tve_bind,
+       .unbind = imx_tve_unbind,
+};
+
+static int imx_tve_probe(struct platform_device *pdev)
+{
+       return component_add(&pdev->dev, &imx_tve_ops);
+}
+
+static int imx_tve_remove(struct platform_device *pdev)
+{
+       component_del(&pdev->dev, &imx_tve_ops);
+       return 0;
+}
+
+static const struct of_device_id imx_tve_dt_ids[] = {
+       { .compatible = "fsl,imx53-tve", },
+       { /* sentinel */ }
+};
+
+static struct platform_driver imx_tve_driver = {
+       .probe          = imx_tve_probe,
+       .remove         = imx_tve_remove,
+       .driver         = {
+               .of_match_table = imx_tve_dt_ids,
+               .name   = "imx-tve",
+               .owner  = THIS_MODULE,
+       },
+};
+
+module_platform_driver(imx_tve_driver);
+
+MODULE_DESCRIPTION("i.MX Television Encoder driver");
+MODULE_AUTHOR("Philipp Zabel, Pengutronix");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-tve");
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
new file mode 100644 (file)
index 0000000..11e84a2
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * i.MX IPUv3 Graphics driver
+ *
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <linux/fb.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include <video/imx-ipu-v3.h>
+#include "imx-drm.h"
+#include "ipuv3-plane.h"
+
+#define DRIVER_DESC            "i.MX IPUv3 Graphics"
+
+struct ipu_crtc {
+       struct device           *dev;
+       struct drm_crtc         base;
+       struct imx_drm_crtc     *imx_crtc;
+
+       /* plane[0] is the full plane, plane[1] is the partial plane */
+       struct ipu_plane        *plane[2];
+
+       struct ipu_dc           *dc;
+       struct ipu_di           *di;
+       int                     enabled;
+       struct drm_pending_vblank_event *page_flip_event;
+       struct drm_framebuffer  *newfb;
+       int                     irq;
+       u32                     interface_pix_fmt;
+       unsigned long           di_clkflags;
+       int                     di_hsync_pin;
+       int                     di_vsync_pin;
+};
+
+#define to_ipu_crtc(x) container_of(x, struct ipu_crtc, base)
+
+static void ipu_fb_enable(struct ipu_crtc *ipu_crtc)
+{
+       struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+
+       if (ipu_crtc->enabled)
+               return;
+
+       ipu_dc_enable(ipu);
+       ipu_plane_enable(ipu_crtc->plane[0]);
+       /* Start DC channel and DI after IDMAC */
+       ipu_dc_enable_channel(ipu_crtc->dc);
+       ipu_di_enable(ipu_crtc->di);
+
+       ipu_crtc->enabled = 1;
+}
+
+static void ipu_fb_disable(struct ipu_crtc *ipu_crtc)
+{
+       struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+
+       if (!ipu_crtc->enabled)
+               return;
+
+       /* Stop DC channel and DI before IDMAC */
+       ipu_dc_disable_channel(ipu_crtc->dc);
+       ipu_di_disable(ipu_crtc->di);
+       ipu_plane_disable(ipu_crtc->plane[0]);
+       ipu_dc_disable(ipu);
+
+       ipu_crtc->enabled = 0;
+}
+
+static void ipu_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+       dev_dbg(ipu_crtc->dev, "%s mode: %d\n", __func__, mode);
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               ipu_fb_enable(ipu_crtc);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               ipu_fb_disable(ipu_crtc);
+               break;
+       }
+}
+
+static int ipu_page_flip(struct drm_crtc *crtc,
+               struct drm_framebuffer *fb,
+               struct drm_pending_vblank_event *event,
+               uint32_t page_flip_flags)
+{
+       struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+       int ret;
+
+       if (ipu_crtc->newfb)
+               return -EBUSY;
+
+       ret = imx_drm_crtc_vblank_get(ipu_crtc->imx_crtc);
+       if (ret) {
+               dev_dbg(ipu_crtc->dev, "failed to acquire vblank counter\n");
+               list_del(&event->base.link);
+
+               return ret;
+       }
+
+       ipu_crtc->newfb = fb;
+       ipu_crtc->page_flip_event = event;
+       crtc->primary->fb = fb;
+
+       return 0;
+}
+
+static const struct drm_crtc_funcs ipu_crtc_funcs = {
+       .set_config = drm_crtc_helper_set_config,
+       .destroy = drm_crtc_cleanup,
+       .page_flip = ipu_page_flip,
+};
+
+static int ipu_crtc_mode_set(struct drm_crtc *crtc,
+                              struct drm_display_mode *orig_mode,
+                              struct drm_display_mode *mode,
+                              int x, int y,
+                              struct drm_framebuffer *old_fb)
+{
+       struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+       int ret;
+       struct ipu_di_signal_cfg sig_cfg = {};
+       u32 out_pixel_fmt;
+
+       dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__,
+                       mode->hdisplay);
+       dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__,
+                       mode->vdisplay);
+
+       out_pixel_fmt = ipu_crtc->interface_pix_fmt;
+
+       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+               sig_cfg.interlaced = 1;
+       if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+               sig_cfg.Hsync_pol = 1;
+       if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+               sig_cfg.Vsync_pol = 1;
+
+       sig_cfg.enable_pol = 1;
+       sig_cfg.clk_pol = 0;
+       sig_cfg.width = mode->hdisplay;
+       sig_cfg.height = mode->vdisplay;
+       sig_cfg.pixel_fmt = out_pixel_fmt;
+       sig_cfg.h_start_width = mode->htotal - mode->hsync_end;
+       sig_cfg.h_sync_width = mode->hsync_end - mode->hsync_start;
+       sig_cfg.h_end_width = mode->hsync_start - mode->hdisplay;
+
+       sig_cfg.v_start_width = mode->vtotal - mode->vsync_end;
+       sig_cfg.v_sync_width = mode->vsync_end - mode->vsync_start;
+       sig_cfg.v_end_width = mode->vsync_start - mode->vdisplay;
+       sig_cfg.pixelclock = mode->clock * 1000;
+       sig_cfg.clkflags = ipu_crtc->di_clkflags;
+
+       sig_cfg.v_to_h_sync = 0;
+
+       sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin;
+       sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin;
+
+       ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, sig_cfg.interlaced,
+                       out_pixel_fmt, mode->hdisplay);
+       if (ret) {
+               dev_err(ipu_crtc->dev,
+                               "initializing display controller failed with %d\n",
+                               ret);
+               return ret;
+       }
+
+       ret = ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg);
+       if (ret) {
+               dev_err(ipu_crtc->dev,
+                               "initializing panel failed with %d\n", ret);
+               return ret;
+       }
+
+       return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode,
+                                 crtc->primary->fb,
+                                 0, 0, mode->hdisplay, mode->vdisplay,
+                                 x, y, mode->hdisplay, mode->vdisplay);
+}
+
+static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc)
+{
+       unsigned long flags;
+       struct drm_device *drm = ipu_crtc->base.dev;
+
+       spin_lock_irqsave(&drm->event_lock, flags);
+       if (ipu_crtc->page_flip_event)
+               drm_send_vblank_event(drm, -1, ipu_crtc->page_flip_event);
+       ipu_crtc->page_flip_event = NULL;
+       imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc);
+       spin_unlock_irqrestore(&drm->event_lock, flags);
+}
+
+static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
+{
+       struct ipu_crtc *ipu_crtc = dev_id;
+
+       imx_drm_handle_vblank(ipu_crtc->imx_crtc);
+
+       if (ipu_crtc->newfb) {
+               struct ipu_plane *plane = ipu_crtc->plane[0];
+
+               ipu_crtc->newfb = NULL;
+               ipu_plane_set_base(plane, ipu_crtc->base.primary->fb,
+                                  plane->x, plane->y);
+               ipu_crtc_handle_pageflip(ipu_crtc);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc,
+                                 const struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void ipu_crtc_prepare(struct drm_crtc *crtc)
+{
+       struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+       ipu_fb_disable(ipu_crtc);
+}
+
+static void ipu_crtc_commit(struct drm_crtc *crtc)
+{
+       struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+       ipu_fb_enable(ipu_crtc);
+}
+
+static struct drm_crtc_helper_funcs ipu_helper_funcs = {
+       .dpms = ipu_crtc_dpms,
+       .mode_fixup = ipu_crtc_mode_fixup,
+       .mode_set = ipu_crtc_mode_set,
+       .prepare = ipu_crtc_prepare,
+       .commit = ipu_crtc_commit,
+};
+
+static int ipu_enable_vblank(struct drm_crtc *crtc)
+{
+       return 0;
+}
+
+static void ipu_disable_vblank(struct drm_crtc *crtc)
+{
+       struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+       ipu_crtc->page_flip_event = NULL;
+       ipu_crtc->newfb = NULL;
+}
+
+static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
+               u32 pixfmt, int hsync_pin, int vsync_pin)
+{
+       struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+       ipu_crtc->interface_pix_fmt = pixfmt;
+       ipu_crtc->di_hsync_pin = hsync_pin;
+       ipu_crtc->di_vsync_pin = vsync_pin;
+
+       switch (encoder_type) {
+       case DRM_MODE_ENCODER_DAC:
+       case DRM_MODE_ENCODER_TVDAC:
+       case DRM_MODE_ENCODER_LVDS:
+               ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC |
+                       IPU_DI_CLKMODE_EXT;
+               break;
+       case DRM_MODE_ENCODER_TMDS:
+       case DRM_MODE_ENCODER_NONE:
+               ipu_crtc->di_clkflags = 0;
+               break;
+       }
+
+       return 0;
+}
+
+static const struct imx_drm_crtc_helper_funcs ipu_crtc_helper_funcs = {
+       .enable_vblank = ipu_enable_vblank,
+       .disable_vblank = ipu_disable_vblank,
+       .set_interface_pix_fmt = ipu_set_interface_pix_fmt,
+       .crtc_funcs = &ipu_crtc_funcs,
+       .crtc_helper_funcs = &ipu_helper_funcs,
+};
+
+static void ipu_put_resources(struct ipu_crtc *ipu_crtc)
+{
+       if (!IS_ERR_OR_NULL(ipu_crtc->dc))
+               ipu_dc_put(ipu_crtc->dc);
+       if (!IS_ERR_OR_NULL(ipu_crtc->di))
+               ipu_di_put(ipu_crtc->di);
+}
+
+static int ipu_get_resources(struct ipu_crtc *ipu_crtc,
+               struct ipu_client_platformdata *pdata)
+{
+       struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+       int ret;
+
+       ipu_crtc->dc = ipu_dc_get(ipu, pdata->dc);
+       if (IS_ERR(ipu_crtc->dc)) {
+               ret = PTR_ERR(ipu_crtc->dc);
+               goto err_out;
+       }
+
+       ipu_crtc->di = ipu_di_get(ipu, pdata->di);
+       if (IS_ERR(ipu_crtc->di)) {
+               ret = PTR_ERR(ipu_crtc->di);
+               goto err_out;
+       }
+
+       return 0;
+err_out:
+       ipu_put_resources(ipu_crtc);
+
+       return ret;
+}
+
+static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
+       struct ipu_client_platformdata *pdata, struct drm_device *drm)
+{
+       struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+       int dp = -EINVAL;
+       int ret;
+       int id;
+
+       ret = ipu_get_resources(ipu_crtc, pdata);
+       if (ret) {
+               dev_err(ipu_crtc->dev, "getting resources failed with %d.\n",
+                               ret);
+               return ret;
+       }
+
+       ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc,
+                       &ipu_crtc_helper_funcs, ipu_crtc->dev->of_node);
+       if (ret) {
+               dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
+               goto err_put_resources;
+       }
+
+       if (pdata->dp >= 0)
+               dp = IPU_DP_FLOW_SYNC_BG;
+       id = imx_drm_crtc_id(ipu_crtc->imx_crtc);
+       ipu_crtc->plane[0] = ipu_plane_init(ipu_crtc->base.dev, ipu,
+                                           pdata->dma[0], dp, BIT(id), true);
+       ret = ipu_plane_get_resources(ipu_crtc->plane[0]);
+       if (ret) {
+               dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n",
+                       ret);
+               goto err_remove_crtc;
+       }
+
+       /* If this crtc is using the DP, add an overlay plane */
+       if (pdata->dp >= 0 && pdata->dma[1] > 0) {
+               ipu_crtc->plane[1] = ipu_plane_init(ipu_crtc->base.dev, ipu,
+                                                   pdata->dma[1],
+                                                   IPU_DP_FLOW_SYNC_FG,
+                                                   BIT(id), false);
+               if (IS_ERR(ipu_crtc->plane[1]))
+                       ipu_crtc->plane[1] = NULL;
+       }
+
+       ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]);
+       ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, 0,
+                       "imx_drm", ipu_crtc);
+       if (ret < 0) {
+               dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret);
+               goto err_put_plane_res;
+       }
+
+       return 0;
+
+err_put_plane_res:
+       ipu_plane_put_resources(ipu_crtc->plane[0]);
+err_remove_crtc:
+       imx_drm_remove_crtc(ipu_crtc->imx_crtc);
+err_put_resources:
+       ipu_put_resources(ipu_crtc);
+
+       return ret;
+}
+
+static struct device_node *ipu_drm_get_port_by_id(struct device_node *parent,
+                                                 int port_id)
+{
+       struct device_node *port;
+       int id, ret;
+
+       port = of_get_child_by_name(parent, "port");
+       while (port) {
+               ret = of_property_read_u32(port, "reg", &id);
+               if (!ret && id == port_id)
+                       return port;
+
+               do {
+                       port = of_get_next_child(parent, port);
+                       if (!port)
+                               return NULL;
+               } while (of_node_cmp(port->name, "port"));
+       }
+
+       return NULL;
+}
+
+static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
+{
+       struct ipu_client_platformdata *pdata = dev->platform_data;
+       struct drm_device *drm = data;
+       struct ipu_crtc *ipu_crtc;
+       int ret;
+
+       ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL);
+       if (!ipu_crtc)
+               return -ENOMEM;
+
+       ipu_crtc->dev = dev;
+
+       ret = ipu_crtc_init(ipu_crtc, pdata, drm);
+       if (ret)
+               return ret;
+
+       dev_set_drvdata(dev, ipu_crtc);
+
+       return 0;
+}
+
+static void ipu_drm_unbind(struct device *dev, struct device *master,
+       void *data)
+{
+       struct ipu_crtc *ipu_crtc = dev_get_drvdata(dev);
+
+       imx_drm_remove_crtc(ipu_crtc->imx_crtc);
+
+       ipu_plane_put_resources(ipu_crtc->plane[0]);
+       ipu_put_resources(ipu_crtc);
+}
+
+static const struct component_ops ipu_crtc_ops = {
+       .bind = ipu_drm_bind,
+       .unbind = ipu_drm_unbind,
+};
+
+static int ipu_drm_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ipu_client_platformdata *pdata = dev->platform_data;
+       int ret;
+
+       if (!dev->platform_data)
+               return -EINVAL;
+
+       if (!dev->of_node) {
+               /* Associate crtc device with the corresponding DI port node */
+               dev->of_node = ipu_drm_get_port_by_id(dev->parent->of_node,
+                                                     pdata->di + 2);
+               if (!dev->of_node) {
+                       dev_err(dev, "missing port@%d node in %s\n",
+                               pdata->di + 2, dev->parent->of_node->full_name);
+                       return -ENODEV;
+               }
+       }
+
+       ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
+
+       return component_add(dev, &ipu_crtc_ops);
+}
+
+static int ipu_drm_remove(struct platform_device *pdev)
+{
+       component_del(&pdev->dev, &ipu_crtc_ops);
+       return 0;
+}
+
+static struct platform_driver ipu_drm_driver = {
+       .driver = {
+               .name = "imx-ipuv3-crtc",
+       },
+       .probe = ipu_drm_probe,
+       .remove = ipu_drm_remove,
+};
+module_platform_driver(ipu_drm_driver);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-ipuv3-crtc");
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c
new file mode 100644 (file)
index 0000000..944962b
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * i.MX IPUv3 DP Overlay Planes
+ *
+ * Copyright (C) 2013 Philipp Zabel, Pengutronix
+ *
+ * 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 <drm/drmP.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "video/imx-ipu-v3.h"
+#include "ipuv3-plane.h"
+
+#define to_ipu_plane(x)        container_of(x, struct ipu_plane, base)
+
+static const uint32_t ipu_plane_formats[] = {
+       DRM_FORMAT_XRGB1555,
+       DRM_FORMAT_XBGR1555,
+       DRM_FORMAT_ARGB8888,
+       DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_ABGR8888,
+       DRM_FORMAT_XBGR8888,
+       DRM_FORMAT_YUYV,
+       DRM_FORMAT_YVYU,
+       DRM_FORMAT_YUV420,
+       DRM_FORMAT_YVU420,
+};
+
+int ipu_plane_irq(struct ipu_plane *ipu_plane)
+{
+       return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch,
+                                    IPU_IRQ_EOF);
+}
+
+static int calc_vref(struct drm_display_mode *mode)
+{
+       unsigned long htotal, vtotal;
+
+       htotal = mode->htotal;
+       vtotal = mode->vtotal;
+
+       if (!htotal || !vtotal)
+               return 60;
+
+       return DIV_ROUND_UP(mode->clock * 1000, vtotal * htotal);
+}
+
+static inline int calc_bandwidth(int width, int height, unsigned int vref)
+{
+       return width * height * vref;
+}
+
+int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
+                      int x, int y)
+{
+       struct drm_gem_cma_object *cma_obj;
+       unsigned long eba;
+
+       cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+       if (!cma_obj) {
+               DRM_DEBUG_KMS("entry is null.\n");
+               return -EFAULT;
+       }
+
+       dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
+               &cma_obj->paddr, x, y);
+
+       ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
+
+       eba = cma_obj->paddr + fb->offsets[0] +
+             fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x;
+       ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
+       ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
+
+       /* cache offsets for subsequent pageflips */
+       ipu_plane->x = x;
+       ipu_plane->y = y;
+
+       return 0;
+}
+
+int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
+                      struct drm_display_mode *mode,
+                      struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+                      unsigned int crtc_w, unsigned int crtc_h,
+                      uint32_t src_x, uint32_t src_y,
+                      uint32_t src_w, uint32_t src_h)
+{
+       struct device *dev = ipu_plane->base.dev->dev;
+       int ret;
+
+       /* no scaling */
+       if (src_w != crtc_w || src_h != crtc_h)
+               return -EINVAL;
+
+       /* clip to crtc bounds */
+       if (crtc_x < 0) {
+               if (-crtc_x > crtc_w)
+                       return -EINVAL;
+               src_x += -crtc_x;
+               src_w -= -crtc_x;
+               crtc_w -= -crtc_x;
+               crtc_x = 0;
+       }
+       if (crtc_y < 0) {
+               if (-crtc_y > crtc_h)
+                       return -EINVAL;
+               src_y += -crtc_y;
+               src_h -= -crtc_y;
+               crtc_h -= -crtc_y;
+               crtc_y = 0;
+       }
+       if (crtc_x + crtc_w > mode->hdisplay) {
+               if (crtc_x > mode->hdisplay)
+                       return -EINVAL;
+               crtc_w = mode->hdisplay - crtc_x;
+               src_w = crtc_w;
+       }
+       if (crtc_y + crtc_h > mode->vdisplay) {
+               if (crtc_y > mode->vdisplay)
+                       return -EINVAL;
+               crtc_h = mode->vdisplay - crtc_y;
+               src_h = crtc_h;
+       }
+       /* full plane minimum width is 13 pixels */
+       if (crtc_w < 13 && (ipu_plane->dp_flow != IPU_DP_FLOW_SYNC_FG))
+               return -EINVAL;
+       if (crtc_h < 2)
+               return -EINVAL;
+
+       switch (ipu_plane->dp_flow) {
+       case IPU_DP_FLOW_SYNC_BG:
+               ret = ipu_dp_setup_channel(ipu_plane->dp,
+                               IPUV3_COLORSPACE_RGB,
+                               IPUV3_COLORSPACE_RGB);
+               if (ret) {
+                       dev_err(dev,
+                               "initializing display processor failed with %d\n",
+                               ret);
+                       return ret;
+               }
+               ipu_dp_set_global_alpha(ipu_plane->dp, 1, 0, 1);
+               break;
+       case IPU_DP_FLOW_SYNC_FG:
+               ipu_dp_setup_channel(ipu_plane->dp,
+                               ipu_drm_fourcc_to_colorspace(fb->pixel_format),
+                               IPUV3_COLORSPACE_UNKNOWN);
+               ipu_dp_set_window_pos(ipu_plane->dp, crtc_x, crtc_y);
+               break;
+       }
+
+       ret = ipu_dmfc_init_channel(ipu_plane->dmfc, crtc_w);
+       if (ret) {
+               dev_err(dev, "initializing dmfc channel failed with %d\n", ret);
+               return ret;
+       }
+
+       ret = ipu_dmfc_alloc_bandwidth(ipu_plane->dmfc,
+                       calc_bandwidth(crtc_w, crtc_h,
+                                      calc_vref(mode)), 64);
+       if (ret) {
+               dev_err(dev, "allocating dmfc bandwidth failed with %d\n", ret);
+               return ret;
+       }
+
+       ipu_cpmem_zero(ipu_plane->ipu_ch);
+       ipu_cpmem_set_resolution(ipu_plane->ipu_ch, src_w, src_h);
+       ret = ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->pixel_format);
+       if (ret < 0) {
+               dev_err(dev, "unsupported pixel format 0x%08x\n",
+                       fb->pixel_format);
+               return ret;
+       }
+       ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
+
+       ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
+{
+       if (!IS_ERR_OR_NULL(ipu_plane->dp))
+               ipu_dp_put(ipu_plane->dp);
+       if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
+               ipu_dmfc_put(ipu_plane->dmfc);
+       if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch))
+               ipu_idmac_put(ipu_plane->ipu_ch);
+}
+
+int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
+{
+       int ret;
+
+       ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma);
+       if (IS_ERR(ipu_plane->ipu_ch)) {
+               ret = PTR_ERR(ipu_plane->ipu_ch);
+               DRM_ERROR("failed to get idmac channel: %d\n", ret);
+               return ret;
+       }
+
+       ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma);
+       if (IS_ERR(ipu_plane->dmfc)) {
+               ret = PTR_ERR(ipu_plane->dmfc);
+               DRM_ERROR("failed to get dmfc: ret %d\n", ret);
+               goto err_out;
+       }
+
+       if (ipu_plane->dp_flow >= 0) {
+               ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow);
+               if (IS_ERR(ipu_plane->dp)) {
+                       ret = PTR_ERR(ipu_plane->dp);
+                       DRM_ERROR("failed to get dp flow: %d\n", ret);
+                       goto err_out;
+               }
+       }
+
+       return 0;
+err_out:
+       ipu_plane_put_resources(ipu_plane);
+
+       return ret;
+}
+
+void ipu_plane_enable(struct ipu_plane *ipu_plane)
+{
+       if (ipu_plane->dp)
+               ipu_dp_enable(ipu_plane->ipu);
+       ipu_dmfc_enable_channel(ipu_plane->dmfc);
+       ipu_idmac_enable_channel(ipu_plane->ipu_ch);
+       if (ipu_plane->dp)
+               ipu_dp_enable_channel(ipu_plane->dp);
+
+       ipu_plane->enabled = true;
+}
+
+void ipu_plane_disable(struct ipu_plane *ipu_plane)
+{
+       ipu_plane->enabled = false;
+
+       ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
+
+       if (ipu_plane->dp)
+               ipu_dp_disable_channel(ipu_plane->dp);
+       ipu_idmac_disable_channel(ipu_plane->ipu_ch);
+       ipu_dmfc_disable_channel(ipu_plane->dmfc);
+       if (ipu_plane->dp)
+               ipu_dp_disable(ipu_plane->ipu);
+}
+
+/*
+ * drm_plane API
+ */
+
+static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
+                           struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+                           unsigned int crtc_w, unsigned int crtc_h,
+                           uint32_t src_x, uint32_t src_y,
+                           uint32_t src_w, uint32_t src_h)
+{
+       struct ipu_plane *ipu_plane = to_ipu_plane(plane);
+       int ret = 0;
+
+       DRM_DEBUG_KMS("plane - %p\n", plane);
+
+       if (!ipu_plane->enabled)
+               ret = ipu_plane_get_resources(ipu_plane);
+       if (ret < 0)
+               return ret;
+
+       ret = ipu_plane_mode_set(ipu_plane, crtc, &crtc->hwmode, fb,
+                       crtc_x, crtc_y, crtc_w, crtc_h,
+                       src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16);
+       if (ret < 0) {
+               ipu_plane_put_resources(ipu_plane);
+               return ret;
+       }
+
+       if (crtc != plane->crtc)
+               dev_info(plane->dev->dev, "crtc change: %p -> %p\n",
+                               plane->crtc, crtc);
+       plane->crtc = crtc;
+
+       if (!ipu_plane->enabled)
+               ipu_plane_enable(ipu_plane);
+
+       return 0;
+}
+
+static int ipu_disable_plane(struct drm_plane *plane)
+{
+       struct ipu_plane *ipu_plane = to_ipu_plane(plane);
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       if (ipu_plane->enabled)
+               ipu_plane_disable(ipu_plane);
+
+       ipu_plane_put_resources(ipu_plane);
+
+       return 0;
+}
+
+static void ipu_plane_destroy(struct drm_plane *plane)
+{
+       struct ipu_plane *ipu_plane = to_ipu_plane(plane);
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       ipu_disable_plane(plane);
+       drm_plane_cleanup(plane);
+       kfree(ipu_plane);
+}
+
+static struct drm_plane_funcs ipu_plane_funcs = {
+       .update_plane   = ipu_update_plane,
+       .disable_plane  = ipu_disable_plane,
+       .destroy        = ipu_plane_destroy,
+};
+
+struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
+                                int dma, int dp, unsigned int possible_crtcs,
+                                bool priv)
+{
+       struct ipu_plane *ipu_plane;
+       int ret;
+
+       DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
+                     dma, dp, possible_crtcs);
+
+       ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL);
+       if (!ipu_plane) {
+               DRM_ERROR("failed to allocate plane\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       ipu_plane->ipu = ipu;
+       ipu_plane->dma = dma;
+       ipu_plane->dp_flow = dp;
+
+       ret = drm_plane_init(dev, &ipu_plane->base, possible_crtcs,
+                            &ipu_plane_funcs, ipu_plane_formats,
+                            ARRAY_SIZE(ipu_plane_formats),
+                            priv);
+       if (ret) {
+               DRM_ERROR("failed to initialize plane\n");
+               kfree(ipu_plane);
+               return ERR_PTR(ret);
+       }
+
+       return ipu_plane;
+}
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.h b/drivers/gpu/drm/imx/ipuv3-plane.h
new file mode 100644 (file)
index 0000000..c0aae5b
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef __IPUV3_PLANE_H__
+#define __IPUV3_PLANE_H__
+
+#include <drm/drm_crtc.h> /* drm_plane */
+
+struct drm_plane;
+struct drm_device;
+struct ipu_soc;
+struct drm_crtc;
+struct drm_framebuffer;
+
+struct ipuv3_channel;
+struct dmfc_channel;
+struct ipu_dp;
+
+struct ipu_plane {
+       struct drm_plane        base;
+
+       struct ipu_soc          *ipu;
+       struct ipuv3_channel    *ipu_ch;
+       struct dmfc_channel     *dmfc;
+       struct ipu_dp           *dp;
+
+       int                     dma;
+       int                     dp_flow;
+
+       int                     x;
+       int                     y;
+
+       bool                    enabled;
+};
+
+struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
+                                int dma, int dp, unsigned int possible_crtcs,
+                                bool priv);
+
+/* Init IDMAC, DMFC, DP */
+int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc,
+                      struct drm_display_mode *mode,
+                      struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+                      unsigned int crtc_w, unsigned int crtc_h,
+                      uint32_t src_x, uint32_t src_y, uint32_t src_w,
+                      uint32_t src_h);
+
+void ipu_plane_enable(struct ipu_plane *plane);
+void ipu_plane_disable(struct ipu_plane *plane);
+int ipu_plane_set_base(struct ipu_plane *plane, struct drm_framebuffer *fb,
+                      int x, int y);
+
+int ipu_plane_get_resources(struct ipu_plane *plane);
+void ipu_plane_put_resources(struct ipu_plane *plane);
+
+int ipu_plane_irq(struct ipu_plane *plane);
+
+#endif
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
new file mode 100644 (file)
index 0000000..015a454
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * i.MX drm driver - parallel display implementation
+ *
+ * Copyright (C) 2012 Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/component.h>
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_panel.h>
+#include <linux/videodev2.h>
+#include <video/of_display_timing.h>
+
+#include "imx-drm.h"
+
+#define con_to_imxpd(x) container_of(x, struct imx_parallel_display, connector)
+#define enc_to_imxpd(x) container_of(x, struct imx_parallel_display, encoder)
+
+struct imx_parallel_display {
+       struct drm_connector connector;
+       struct drm_encoder encoder;
+       struct device *dev;
+       void *edid;
+       int edid_len;
+       u32 interface_pix_fmt;
+       int mode_valid;
+       struct drm_display_mode mode;
+       struct drm_panel *panel;
+};
+
+static enum drm_connector_status imx_pd_connector_detect(
+               struct drm_connector *connector, bool force)
+{
+       return connector_status_connected;
+}
+
+static int imx_pd_connector_get_modes(struct drm_connector *connector)
+{
+       struct imx_parallel_display *imxpd = con_to_imxpd(connector);
+       struct device_node *np = imxpd->dev->of_node;
+       int num_modes = 0;
+
+       if (imxpd->panel && imxpd->panel->funcs &&
+           imxpd->panel->funcs->get_modes) {
+               num_modes = imxpd->panel->funcs->get_modes(imxpd->panel);
+               if (num_modes > 0)
+                       return num_modes;
+       }
+
+       if (imxpd->edid) {
+               drm_mode_connector_update_edid_property(connector, imxpd->edid);
+               num_modes = drm_add_edid_modes(connector, imxpd->edid);
+       }
+
+       if (imxpd->mode_valid) {
+               struct drm_display_mode *mode = drm_mode_create(connector->dev);
+
+               if (!mode)
+                       return -EINVAL;
+               drm_mode_copy(mode, &imxpd->mode);
+               mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+               drm_mode_probed_add(connector, mode);
+               num_modes++;
+       }
+
+       if (np) {
+               struct drm_display_mode *mode = drm_mode_create(connector->dev);
+
+               if (!mode)
+                       return -EINVAL;
+               of_get_drm_display_mode(np, &imxpd->mode, OF_USE_NATIVE_MODE);
+               drm_mode_copy(mode, &imxpd->mode);
+               mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+               drm_mode_probed_add(connector, mode);
+               num_modes++;
+       }
+
+       return num_modes;
+}
+
+static struct drm_encoder *imx_pd_connector_best_encoder(
+               struct drm_connector *connector)
+{
+       struct imx_parallel_display *imxpd = con_to_imxpd(connector);
+
+       return &imxpd->encoder;
+}
+
+static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
+
+       if (mode != DRM_MODE_DPMS_ON)
+               drm_panel_disable(imxpd->panel);
+       else
+               drm_panel_enable(imxpd->panel);
+}
+
+static bool imx_pd_encoder_mode_fixup(struct drm_encoder *encoder,
+                          const struct drm_display_mode *mode,
+                          struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void imx_pd_encoder_prepare(struct drm_encoder *encoder)
+{
+       struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
+
+       imx_drm_panel_format(encoder, imxpd->interface_pix_fmt);
+}
+
+static void imx_pd_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+static void imx_pd_encoder_mode_set(struct drm_encoder *encoder,
+                        struct drm_display_mode *mode,
+                        struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void imx_pd_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static struct drm_connector_funcs imx_pd_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .detect = imx_pd_connector_detect,
+       .destroy = imx_drm_connector_destroy,
+};
+
+static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
+       .get_modes = imx_pd_connector_get_modes,
+       .best_encoder = imx_pd_connector_best_encoder,
+};
+
+static struct drm_encoder_funcs imx_pd_encoder_funcs = {
+       .destroy = imx_drm_encoder_destroy,
+};
+
+static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
+       .dpms = imx_pd_encoder_dpms,
+       .mode_fixup = imx_pd_encoder_mode_fixup,
+       .prepare = imx_pd_encoder_prepare,
+       .commit = imx_pd_encoder_commit,
+       .mode_set = imx_pd_encoder_mode_set,
+       .disable = imx_pd_encoder_disable,
+};
+
+static int imx_pd_register(struct drm_device *drm,
+       struct imx_parallel_display *imxpd)
+{
+       int ret;
+
+       ret = imx_drm_encoder_parse_of(drm, &imxpd->encoder,
+                                      imxpd->dev->of_node);
+       if (ret)
+               return ret;
+
+       /* set the connector's dpms to OFF so that
+        * drm_helper_connector_dpms() won't return
+        * immediately since the current state is ON
+        * at this point.
+        */
+       imxpd->connector.dpms = DRM_MODE_DPMS_OFF;
+
+       drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs);
+       drm_encoder_init(drm, &imxpd->encoder, &imx_pd_encoder_funcs,
+                        DRM_MODE_ENCODER_NONE);
+
+       drm_connector_helper_add(&imxpd->connector,
+                       &imx_pd_connector_helper_funcs);
+       drm_connector_init(drm, &imxpd->connector, &imx_pd_connector_funcs,
+                          DRM_MODE_CONNECTOR_VGA);
+
+       if (imxpd->panel)
+               drm_panel_attach(imxpd->panel, &imxpd->connector);
+
+       drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
+
+       imxpd->connector.encoder = &imxpd->encoder;
+
+       return 0;
+}
+
+static int imx_pd_bind(struct device *dev, struct device *master, void *data)
+{
+       struct drm_device *drm = data;
+       struct device_node *np = dev->of_node;
+       struct device_node *panel_node;
+       const u8 *edidp;
+       struct imx_parallel_display *imxpd;
+       int ret;
+       const char *fmt;
+
+       imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL);
+       if (!imxpd)
+               return -ENOMEM;
+
+       edidp = of_get_property(np, "edid", &imxpd->edid_len);
+       if (edidp)
+               imxpd->edid = kmemdup(edidp, imxpd->edid_len, GFP_KERNEL);
+
+       ret = of_property_read_string(np, "interface-pix-fmt", &fmt);
+       if (!ret) {
+               if (!strcmp(fmt, "rgb24"))
+                       imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB24;
+               else if (!strcmp(fmt, "rgb565"))
+                       imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565;
+               else if (!strcmp(fmt, "bgr666"))
+                       imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666;
+               else if (!strcmp(fmt, "lvds666"))
+                       imxpd->interface_pix_fmt =
+                                       v4l2_fourcc('L', 'V', 'D', '6');
+       }
+
+       panel_node = of_parse_phandle(np, "fsl,panel", 0);
+       if (panel_node)
+               imxpd->panel = of_drm_find_panel(panel_node);
+
+       imxpd->dev = dev;
+
+       ret = imx_pd_register(drm, imxpd);
+       if (ret)
+               return ret;
+
+       dev_set_drvdata(dev, imxpd);
+
+       return 0;
+}
+
+static void imx_pd_unbind(struct device *dev, struct device *master,
+       void *data)
+{
+       struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
+
+       imxpd->encoder.funcs->destroy(&imxpd->encoder);
+       imxpd->connector.funcs->destroy(&imxpd->connector);
+}
+
+static const struct component_ops imx_pd_ops = {
+       .bind   = imx_pd_bind,
+       .unbind = imx_pd_unbind,
+};
+
+static int imx_pd_probe(struct platform_device *pdev)
+{
+       return component_add(&pdev->dev, &imx_pd_ops);
+}
+
+static int imx_pd_remove(struct platform_device *pdev)
+{
+       component_del(&pdev->dev, &imx_pd_ops);
+       return 0;
+}
+
+static const struct of_device_id imx_pd_dt_ids[] = {
+       { .compatible = "fsl,imx-parallel-display", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_pd_dt_ids);
+
+static struct platform_driver imx_pd_driver = {
+       .probe          = imx_pd_probe,
+       .remove         = imx_pd_remove,
+       .driver         = {
+               .of_match_table = imx_pd_dt_ids,
+               .name   = "imx-parallel-display",
+               .owner  = THIS_MODULE,
+       },
+};
+
+module_platform_driver(imx_pd_driver);
+
+MODULE_DESCRIPTION("i.MX parallel display driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-parallel-display");
index 9d907c526c94d4df4d9a70a527678c2d58a743ff..5b2a1ff95d3de2ab1341dfa3fe6df3e0986e747e 100644 (file)
@@ -3,6 +3,7 @@ config DRM_MSM
        tristate "MSM DRM"
        depends on DRM
        depends on ARCH_QCOM || (ARM && COMPILE_TEST)
+       select REGULATOR
        select DRM_KMS_HELPER
        select DRM_PANEL
        select SHMEM
index 6283dcb96af51f8bd5e70c26a507412f216996f6..143d988f8addc7471d7962149112f45ec091938f 100644 (file)
@@ -7,6 +7,7 @@ msm-y := \
        adreno/adreno_device.o \
        adreno/adreno_gpu.o \
        adreno/a3xx_gpu.o \
+       adreno/a4xx_gpu.o \
        hdmi/hdmi.o \
        hdmi/hdmi_audio.o \
        hdmi/hdmi_bridge.o \
@@ -24,12 +25,15 @@ msm-y := \
        mdp/mdp4/mdp4_irq.o \
        mdp/mdp4/mdp4_kms.o \
        mdp/mdp4/mdp4_plane.o \
+       mdp/mdp5/mdp5_cfg.o \
+       mdp/mdp5/mdp5_ctl.o \
        mdp/mdp5/mdp5_crtc.o \
        mdp/mdp5/mdp5_encoder.o \
        mdp/mdp5/mdp5_irq.o \
        mdp/mdp5/mdp5_kms.o \
        mdp/mdp5/mdp5_plane.o \
        mdp/mdp5/mdp5_smp.o \
+       msm_atomic.o \
        msm_drv.o \
        msm_fb.o \
        msm_gem.o \
index a3104598c27f8117b5917ab2bdf7c018ad514383..22882cc0a5731c396e7a27075d42116e04193a8a 100644 (file)
@@ -11,10 +11,10 @@ The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (   9859 bytes, from 2014-06-02 15:21:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14960 bytes, from 2014-07-27 17:22:13)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  58020 bytes, from 2014-08-01 12:22:48)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  41068 bytes, from 2014-08-01 12:22:48)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2014-11-13 22:44:30)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  15053 bytes, from 2014-11-09 15:45:47)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  63169 bytes, from 2014-11-13 22:44:18)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  49097 bytes, from 2014-11-14 15:38:00)
 
 Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -926,11 +926,11 @@ static inline uint32_t A2XX_VGT_DRAW_INITIATOR_INDEX_SIZE(enum pc_di_index_size
 #define A2XX_VGT_DRAW_INITIATOR_NOT_EOP                                0x00001000
 #define A2XX_VGT_DRAW_INITIATOR_SMALL_INDEX                    0x00002000
 #define A2XX_VGT_DRAW_INITIATOR_PRE_DRAW_INITIATOR_ENABLE      0x00004000
-#define A2XX_VGT_DRAW_INITIATOR_NUM_INDICES__MASK              0xffff0000
-#define A2XX_VGT_DRAW_INITIATOR_NUM_INDICES__SHIFT             16
-static inline uint32_t A2XX_VGT_DRAW_INITIATOR_NUM_INDICES(uint32_t val)
+#define A2XX_VGT_DRAW_INITIATOR_NUM_INSTANCES__MASK            0xff000000
+#define A2XX_VGT_DRAW_INITIATOR_NUM_INSTANCES__SHIFT           24
+static inline uint32_t A2XX_VGT_DRAW_INITIATOR_NUM_INSTANCES(uint32_t val)
 {
-       return ((val) << A2XX_VGT_DRAW_INITIATOR_NUM_INDICES__SHIFT) & A2XX_VGT_DRAW_INITIATOR_NUM_INDICES__MASK;
+       return ((val) << A2XX_VGT_DRAW_INITIATOR_NUM_INSTANCES__SHIFT) & A2XX_VGT_DRAW_INITIATOR_NUM_INSTANCES__MASK;
 }
 
 #define REG_A2XX_VGT_IMMED_DATA                                        0x000021fd
@@ -1243,13 +1243,13 @@ static inline uint32_t A2XX_CLEAR_COLOR_ALPHA(uint32_t val)
 #define A2XX_PA_SU_POINT_SIZE_HEIGHT__SHIFT                    0
 static inline uint32_t A2XX_PA_SU_POINT_SIZE_HEIGHT(float val)
 {
-       return ((((uint32_t)(val * 8.0))) << A2XX_PA_SU_POINT_SIZE_HEIGHT__SHIFT) & A2XX_PA_SU_POINT_SIZE_HEIGHT__MASK;
+       return ((((uint32_t)(val * 16.0))) << A2XX_PA_SU_POINT_SIZE_HEIGHT__SHIFT) & A2XX_PA_SU_POINT_SIZE_HEIGHT__MASK;
 }
 #define A2XX_PA_SU_POINT_SIZE_WIDTH__MASK                      0xffff0000
 #define A2XX_PA_SU_POINT_SIZE_WIDTH__SHIFT                     16
 static inline uint32_t A2XX_PA_SU_POINT_SIZE_WIDTH(float val)
 {
-       return ((((uint32_t)(val * 8.0))) << A2XX_PA_SU_POINT_SIZE_WIDTH__SHIFT) & A2XX_PA_SU_POINT_SIZE_WIDTH__MASK;
+       return ((((uint32_t)(val * 16.0))) << A2XX_PA_SU_POINT_SIZE_WIDTH__SHIFT) & A2XX_PA_SU_POINT_SIZE_WIDTH__MASK;
 }
 
 #define REG_A2XX_PA_SU_POINT_MINMAX                            0x00002281
@@ -1257,13 +1257,13 @@ static inline uint32_t A2XX_PA_SU_POINT_SIZE_WIDTH(float val)
 #define A2XX_PA_SU_POINT_MINMAX_MIN__SHIFT                     0
 static inline uint32_t A2XX_PA_SU_POINT_MINMAX_MIN(float val)
 {
-       return ((((uint32_t)(val * 8.0))) << A2XX_PA_SU_POINT_MINMAX_MIN__SHIFT) & A2XX_PA_SU_POINT_MINMAX_MIN__MASK;
+       return ((((uint32_t)(val * 16.0))) << A2XX_PA_SU_POINT_MINMAX_MIN__SHIFT) & A2XX_PA_SU_POINT_MINMAX_MIN__MASK;
 }
 #define A2XX_PA_SU_POINT_MINMAX_MAX__MASK                      0xffff0000
 #define A2XX_PA_SU_POINT_MINMAX_MAX__SHIFT                     16
 static inline uint32_t A2XX_PA_SU_POINT_MINMAX_MAX(float val)
 {
-       return ((((uint32_t)(val * 8.0))) << A2XX_PA_SU_POINT_MINMAX_MAX__SHIFT) & A2XX_PA_SU_POINT_MINMAX_MAX__MASK;
+       return ((((uint32_t)(val * 16.0))) << A2XX_PA_SU_POINT_MINMAX_MAX__SHIFT) & A2XX_PA_SU_POINT_MINMAX_MAX__MASK;
 }
 
 #define REG_A2XX_PA_SU_LINE_CNTL                               0x00002282
@@ -1271,7 +1271,7 @@ static inline uint32_t A2XX_PA_SU_POINT_MINMAX_MAX(float val)
 #define A2XX_PA_SU_LINE_CNTL_WIDTH__SHIFT                      0
 static inline uint32_t A2XX_PA_SU_LINE_CNTL_WIDTH(float val)
 {
-       return ((((uint32_t)(val * 8.0))) << A2XX_PA_SU_LINE_CNTL_WIDTH__SHIFT) & A2XX_PA_SU_LINE_CNTL_WIDTH__MASK;
+       return ((((uint32_t)(val * 16.0))) << A2XX_PA_SU_LINE_CNTL_WIDTH__SHIFT) & A2XX_PA_SU_LINE_CNTL_WIDTH__MASK;
 }
 
 #define REG_A2XX_PA_SC_LINE_STIPPLE                            0x00002283
index 82d015279b47bf493fc0b5773c2306387d17c7ce..109e9a263daf6ac8e6d352e0791635e3a76e9ffa 100644 (file)
@@ -11,10 +11,10 @@ The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (   9859 bytes, from 2014-06-02 15:21:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14960 bytes, from 2014-07-27 17:22:13)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  58020 bytes, from 2014-08-01 12:22:48)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  41068 bytes, from 2014-08-01 12:22:48)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2014-11-13 22:44:30)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  15053 bytes, from 2014-11-09 15:45:47)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  63169 bytes, from 2014-11-13 22:44:18)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  49097 bytes, from 2014-11-14 15:38:00)
 
 Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -86,6 +86,14 @@ enum a3xx_vtx_fmt {
        VFMT_NORM_USHORT_16_16 = 29,
        VFMT_NORM_USHORT_16_16_16 = 30,
        VFMT_NORM_USHORT_16_16_16_16 = 31,
+       VFMT_UINT_32 = 32,
+       VFMT_UINT_32_32 = 33,
+       VFMT_UINT_32_32_32 = 34,
+       VFMT_UINT_32_32_32_32 = 35,
+       VFMT_INT_32 = 36,
+       VFMT_INT_32_32 = 37,
+       VFMT_INT_32_32_32 = 38,
+       VFMT_INT_32_32_32_32 = 39,
        VFMT_UBYTE_8 = 40,
        VFMT_UBYTE_8_8 = 41,
        VFMT_UBYTE_8_8_8 = 42,
@@ -112,7 +120,9 @@ enum a3xx_tex_fmt {
        TFMT_NORM_USHORT_565 = 4,
        TFMT_NORM_USHORT_5551 = 6,
        TFMT_NORM_USHORT_4444 = 7,
+       TFMT_NORM_USHORT_Z16 = 9,
        TFMT_NORM_UINT_X8Z24 = 10,
+       TFMT_FLOAT_Z32 = 11,
        TFMT_NORM_UINT_NV12_UV_TILED = 17,
        TFMT_NORM_UINT_NV12_Y_TILED = 19,
        TFMT_NORM_UINT_NV12_UV = 21,
@@ -121,18 +131,38 @@ enum a3xx_tex_fmt {
        TFMT_NORM_UINT_I420_U = 26,
        TFMT_NORM_UINT_I420_V = 27,
        TFMT_NORM_UINT_2_10_10_10 = 41,
+       TFMT_FLOAT_9_9_9_E5 = 42,
+       TFMT_FLOAT_10_11_11 = 43,
        TFMT_NORM_UINT_A8 = 44,
        TFMT_NORM_UINT_L8_A8 = 47,
        TFMT_NORM_UINT_8 = 48,
        TFMT_NORM_UINT_8_8 = 49,
        TFMT_NORM_UINT_8_8_8 = 50,
        TFMT_NORM_UINT_8_8_8_8 = 51,
+       TFMT_NORM_SINT_8_8 = 53,
+       TFMT_NORM_SINT_8_8_8_8 = 55,
+       TFMT_UINT_8_8 = 57,
+       TFMT_UINT_8_8_8_8 = 59,
+       TFMT_SINT_8_8 = 61,
+       TFMT_SINT_8_8_8_8 = 63,
        TFMT_FLOAT_16 = 64,
        TFMT_FLOAT_16_16 = 65,
        TFMT_FLOAT_16_16_16_16 = 67,
+       TFMT_UINT_16 = 68,
+       TFMT_UINT_16_16 = 69,
+       TFMT_UINT_16_16_16_16 = 71,
+       TFMT_SINT_16 = 72,
+       TFMT_SINT_16_16 = 73,
+       TFMT_SINT_16_16_16_16 = 75,
        TFMT_FLOAT_32 = 84,
        TFMT_FLOAT_32_32 = 85,
        TFMT_FLOAT_32_32_32_32 = 87,
+       TFMT_UINT_32 = 88,
+       TFMT_UINT_32_32 = 89,
+       TFMT_UINT_32_32_32_32 = 91,
+       TFMT_SINT_32 = 92,
+       TFMT_SINT_32_32 = 93,
+       TFMT_SINT_32_32_32_32 = 95,
 };
 
 enum a3xx_tex_fetchsize {
@@ -145,19 +175,34 @@ enum a3xx_tex_fetchsize {
 };
 
 enum a3xx_color_fmt {
+       RB_R5G6B5_UNORM = 0,
+       RB_R5G5B5A1_UNORM = 1,
+       RB_R4G4B4A4_UNORM = 3,
        RB_R8G8B8_UNORM = 4,
        RB_R8G8B8A8_UNORM = 8,
-       RB_Z16_UNORM = 12,
+       RB_R8G8B8A8_UINT = 10,
+       RB_R8G8B8A8_SINT = 11,
+       RB_R8G8_UNORM = 12,
+       RB_R8_UINT = 14,
+       RB_R8_SINT = 15,
+       RB_R10G10B10A2_UNORM = 16,
        RB_A8_UNORM = 20,
+       RB_R8_UNORM = 21,
        RB_R16G16B16A16_FLOAT = 27,
+       RB_R11G11B10_FLOAT = 28,
+       RB_R16_SINT = 40,
+       RB_R16G16_SINT = 41,
+       RB_R16G16B16A16_SINT = 43,
+       RB_R16_UINT = 44,
+       RB_R16G16_UINT = 45,
+       RB_R16G16B16A16_UINT = 47,
        RB_R32G32B32A32_FLOAT = 51,
-};
-
-enum a3xx_color_swap {
-       WZYX = 0,
-       WXYZ = 1,
-       ZYXW = 2,
-       XYZW = 3,
+       RB_R32_SINT = 52,
+       RB_R32G32_SINT = 53,
+       RB_R32G32B32A32_SINT = 55,
+       RB_R32_UINT = 56,
+       RB_R32G32_UINT = 57,
+       RB_R32G32B32A32_UINT = 59,
 };
 
 enum a3xx_sp_perfcounter_select {
@@ -194,6 +239,11 @@ enum a3xx_rb_blend_opcode {
        BLEND_MAX_DST_SRC = 4,
 };
 
+enum a3xx_intp_mode {
+       SMOOTH = 0,
+       FLAT = 1,
+};
+
 enum a3xx_tex_filter {
        A3XX_TEX_NEAREST = 0,
        A3XX_TEX_LINEAR = 1,
@@ -536,6 +586,10 @@ enum a3xx_tex_type {
 
 #define REG_A3XX_CP_MEQ_DATA                                   0x000001db
 
+#define REG_A3XX_CP_WFI_PEND_CTR                               0x000001f5
+
+#define REG_A3XX_RBBM_PM_OVERRIDE2                             0x0000039d
+
 #define REG_A3XX_CP_PERFCOUNTER_SELECT                         0x00000445
 
 #define REG_A3XX_CP_HW_FAULT                                   0x0000045c
@@ -550,6 +604,12 @@ static inline uint32_t REG_A3XX_CP_PROTECT_REG(uint32_t i0) { return 0x00000460
 
 #define REG_A3XX_CP_AHB_FAULT                                  0x0000054d
 
+#define REG_A3XX_SQ_GPR_MANAGEMENT                             0x00000d00
+
+#define REG_A3XX_SQ_INST_STORE_MANAGMENT                       0x00000d02
+
+#define REG_A3XX_TP0_CHICKEN                                   0x00000e1e
+
 #define REG_A3XX_SP_GLOBAL_MEM_SIZE                            0x00000e22
 
 #define REG_A3XX_SP_GLOBAL_MEM_ADDR                            0x00000e23
@@ -632,13 +692,13 @@ static inline uint32_t A3XX_GRAS_CL_VPORT_ZSCALE(float val)
 #define A3XX_GRAS_SU_POINT_MINMAX_MIN__SHIFT                   0
 static inline uint32_t A3XX_GRAS_SU_POINT_MINMAX_MIN(float val)
 {
-       return ((((uint32_t)(val * 8.0))) << A3XX_GRAS_SU_POINT_MINMAX_MIN__SHIFT) & A3XX_GRAS_SU_POINT_MINMAX_MIN__MASK;
+       return ((((uint32_t)(val * 16.0))) << A3XX_GRAS_SU_POINT_MINMAX_MIN__SHIFT) & A3XX_GRAS_SU_POINT_MINMAX_MIN__MASK;
 }
 #define A3XX_GRAS_SU_POINT_MINMAX_MAX__MASK                    0xffff0000
 #define A3XX_GRAS_SU_POINT_MINMAX_MAX__SHIFT                   16
 static inline uint32_t A3XX_GRAS_SU_POINT_MINMAX_MAX(float val)
 {
-       return ((((uint32_t)(val * 8.0))) << A3XX_GRAS_SU_POINT_MINMAX_MAX__SHIFT) & A3XX_GRAS_SU_POINT_MINMAX_MAX__MASK;
+       return ((((uint32_t)(val * 16.0))) << A3XX_GRAS_SU_POINT_MINMAX_MAX__SHIFT) & A3XX_GRAS_SU_POINT_MINMAX_MAX__MASK;
 }
 
 #define REG_A3XX_GRAS_SU_POINT_SIZE                            0x00002069
@@ -646,7 +706,7 @@ static inline uint32_t A3XX_GRAS_SU_POINT_MINMAX_MAX(float val)
 #define A3XX_GRAS_SU_POINT_SIZE__SHIFT                         0
 static inline uint32_t A3XX_GRAS_SU_POINT_SIZE(float val)
 {
-       return ((((uint32_t)(val * 8.0))) << A3XX_GRAS_SU_POINT_SIZE__SHIFT) & A3XX_GRAS_SU_POINT_SIZE__MASK;
+       return ((((int32_t)(val * 16.0))) << A3XX_GRAS_SU_POINT_SIZE__SHIFT) & A3XX_GRAS_SU_POINT_SIZE__MASK;
 }
 
 #define REG_A3XX_GRAS_SU_POLY_OFFSET_SCALE                     0x0000206c
@@ -654,7 +714,7 @@ static inline uint32_t A3XX_GRAS_SU_POINT_SIZE(float val)
 #define A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__SHIFT              0
 static inline uint32_t A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL(float val)
 {
-       return ((((uint32_t)(val * 28.0))) << A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__MASK;
+       return ((((int32_t)(val * 16384.0))) << A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__MASK;
 }
 
 #define REG_A3XX_GRAS_SU_POLY_OFFSET_OFFSET                    0x0000206d
@@ -662,7 +722,7 @@ static inline uint32_t A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL(float val)
 #define A3XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT                 0
 static inline uint32_t A3XX_GRAS_SU_POLY_OFFSET_OFFSET(float val)
 {
-       return ((((uint32_t)(val * 28.0))) << A3XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK;
+       return ((((int32_t)(val * 16384.0))) << A3XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK;
 }
 
 #define REG_A3XX_GRAS_SU_MODE_CONTROL                          0x00002070
@@ -673,7 +733,7 @@ static inline uint32_t A3XX_GRAS_SU_POLY_OFFSET_OFFSET(float val)
 #define A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT         3
 static inline uint32_t A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH(float val)
 {
-       return ((((uint32_t)(val * 4.0))) << A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT) & A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK;
+       return ((((int32_t)(val * 4.0))) << A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT) & A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK;
 }
 #define A3XX_GRAS_SU_MODE_CONTROL_POLY_OFFSET                  0x00000800
 
@@ -863,6 +923,7 @@ static inline uint32_t A3XX_RB_MRT_BUF_INFO_COLOR_SWAP(enum a3xx_color_swap val)
 {
        return ((val) << A3XX_RB_MRT_BUF_INFO_COLOR_SWAP__SHIFT) & A3XX_RB_MRT_BUF_INFO_COLOR_SWAP__MASK;
 }
+#define A3XX_RB_MRT_BUF_INFO_COLOR_SRGB                                0x00004000
 #define A3XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__MASK             0xfffe0000
 #define A3XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__SHIFT            17
 static inline uint32_t A3XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH(uint32_t val)
@@ -1001,6 +1062,7 @@ static inline uint32_t A3XX_RB_COPY_CONTROL_FASTCLEAR(uint32_t val)
 {
        return ((val) << A3XX_RB_COPY_CONTROL_FASTCLEAR__SHIFT) & A3XX_RB_COPY_CONTROL_FASTCLEAR__MASK;
 }
+#define A3XX_RB_COPY_CONTROL_UNK12                             0x00001000
 #define A3XX_RB_COPY_CONTROL_GMEM_BASE__MASK                   0xffffc000
 #define A3XX_RB_COPY_CONTROL_GMEM_BASE__SHIFT                  14
 static inline uint32_t A3XX_RB_COPY_CONTROL_GMEM_BASE(uint32_t val)
@@ -1079,7 +1141,7 @@ static inline uint32_t A3XX_RB_DEPTH_CONTROL_ZFUNC(enum adreno_compare_func val)
 #define REG_A3XX_RB_DEPTH_CLEAR                                        0x00002101
 
 #define REG_A3XX_RB_DEPTH_INFO                                 0x00002102
-#define A3XX_RB_DEPTH_INFO_DEPTH_FORMAT__MASK                  0x00000001
+#define A3XX_RB_DEPTH_INFO_DEPTH_FORMAT__MASK                  0x00000003
 #define A3XX_RB_DEPTH_INFO_DEPTH_FORMAT__SHIFT                 0
 static inline uint32_t A3XX_RB_DEPTH_INFO_DEPTH_FORMAT(enum adreno_rb_depth_format val)
 {
@@ -1265,6 +1327,7 @@ static inline uint32_t A3XX_PC_PRIM_VTX_CNTL_POLYMODE_BACK_PTYPE(enum adreno_pa_
 {
        return ((val) << A3XX_PC_PRIM_VTX_CNTL_POLYMODE_BACK_PTYPE__SHIFT) & A3XX_PC_PRIM_VTX_CNTL_POLYMODE_BACK_PTYPE__MASK;
 }
+#define A3XX_PC_PRIM_VTX_CNTL_PRIMITIVE_RESTART                        0x00100000
 #define A3XX_PC_PRIM_VTX_CNTL_PROVOKING_VTX_LAST               0x02000000
 #define A3XX_PC_PRIM_VTX_CNTL_PSIZE                            0x04000000
 
@@ -1281,7 +1344,12 @@ static inline uint32_t A3XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE(enum a3xx_threadsize
 #define A3XX_HLSQ_CONTROL_0_REG_SPSHADERRESTART                        0x00000200
 #define A3XX_HLSQ_CONTROL_0_REG_RESERVED2                      0x00000400
 #define A3XX_HLSQ_CONTROL_0_REG_CHUNKDISABLE                   0x04000000
-#define A3XX_HLSQ_CONTROL_0_REG_CONSTSWITCHMODE                        0x08000000
+#define A3XX_HLSQ_CONTROL_0_REG_CONSTMODE__MASK                        0x08000000
+#define A3XX_HLSQ_CONTROL_0_REG_CONSTMODE__SHIFT               27
+static inline uint32_t A3XX_HLSQ_CONTROL_0_REG_CONSTMODE(uint32_t val)
+{
+       return ((val) << A3XX_HLSQ_CONTROL_0_REG_CONSTMODE__SHIFT) & A3XX_HLSQ_CONTROL_0_REG_CONSTMODE__MASK;
+}
 #define A3XX_HLSQ_CONTROL_0_REG_LAZYUPDATEDISABLE              0x10000000
 #define A3XX_HLSQ_CONTROL_0_REG_SPCONSTFULLUPDATE              0x20000000
 #define A3XX_HLSQ_CONTROL_0_REG_TPFULLUPDATE                   0x40000000
@@ -1484,6 +1552,8 @@ static inline uint32_t A3XX_VFD_CONTROL_1_REGID4INST(uint32_t val)
 
 #define REG_A3XX_VFD_INDEX_OFFSET                              0x00002245
 
+#define REG_A3XX_VFD_INDEX_OFFSET                              0x00002245
+
 static inline uint32_t REG_A3XX_VFD_FETCH(uint32_t i0) { return 0x00002246 + 0x2*i0; }
 
 static inline uint32_t REG_A3XX_VFD_FETCH_INSTR_0(uint32_t i0) { return 0x00002246 + 0x2*i0; }
@@ -1537,6 +1607,7 @@ static inline uint32_t A3XX_VFD_DECODE_INSTR_REGID(uint32_t val)
 {
        return ((val) << A3XX_VFD_DECODE_INSTR_REGID__SHIFT) & A3XX_VFD_DECODE_INSTR_REGID__MASK;
 }
+#define A3XX_VFD_DECODE_INSTR_INT                              0x00100000
 #define A3XX_VFD_DECODE_INSTR_SWAP__MASK                       0x00c00000
 #define A3XX_VFD_DECODE_INSTR_SWAP__SHIFT                      22
 static inline uint32_t A3XX_VFD_DECODE_INSTR_SWAP(enum a3xx_color_swap val)
@@ -1604,6 +1675,102 @@ static inline uint32_t A3XX_VPC_PACK_NUMNONPOSVSVAR(uint32_t val)
 static inline uint32_t REG_A3XX_VPC_VARYING_INTERP(uint32_t i0) { return 0x00002282 + 0x1*i0; }
 
 static inline uint32_t REG_A3XX_VPC_VARYING_INTERP_MODE(uint32_t i0) { return 0x00002282 + 0x1*i0; }
+#define A3XX_VPC_VARYING_INTERP_MODE_C0__MASK                  0x00000003
+#define A3XX_VPC_VARYING_INTERP_MODE_C0__SHIFT                 0
+static inline uint32_t A3XX_VPC_VARYING_INTERP_MODE_C0(enum a3xx_intp_mode val)
+{
+       return ((val) << A3XX_VPC_VARYING_INTERP_MODE_C0__SHIFT) & A3XX_VPC_VARYING_INTERP_MODE_C0__MASK;
+}
+#define A3XX_VPC_VARYING_INTERP_MODE_C1__MASK                  0x0000000c
+#define A3XX_VPC_VARYING_INTERP_MODE_C1__SHIFT                 2
+static inline uint32_t A3XX_VPC_VARYING_INTERP_MODE_C1(enum a3xx_intp_mode val)
+{
+       return ((val) << A3XX_VPC_VARYING_INTERP_MODE_C1__SHIFT) & A3XX_VPC_VARYING_INTERP_MODE_C1__MASK;
+}
+#define A3XX_VPC_VARYING_INTERP_MODE_C2__MASK                  0x00000030
+#define A3XX_VPC_VARYING_INTERP_MODE_C2__SHIFT                 4
+static inline uint32_t A3XX_VPC_VARYING_INTERP_MODE_C2(enum a3xx_intp_mode val)
+{
+       return ((val) << A3XX_VPC_VARYING_INTERP_MODE_C2__SHIFT) & A3XX_VPC_VARYING_INTERP_MODE_C2__MASK;
+}
+#define A3XX_VPC_VARYING_INTERP_MODE_C3__MASK                  0x000000c0
+#define A3XX_VPC_VARYING_INTERP_MODE_C3__SHIFT                 6
+static inline uint32_t A3XX_VPC_VARYING_INTERP_MODE_C3(enum a3xx_intp_mode val)
+{
+       return ((val) << A3XX_VPC_VARYING_INTERP_MODE_C3__SHIFT) & A3XX_VPC_VARYING_INTERP_MODE_C3__MASK;
+}
+#define A3XX_VPC_VARYING_INTERP_MODE_C4__MASK                  0x00000300
+#define A3XX_VPC_VARYING_INTERP_MODE_C4__SHIFT                 8
+static inline uint32_t A3XX_VPC_VARYING_INTERP_MODE_C4(enum a3xx_intp_mode val)
+{
+       return ((val) << A3XX_VPC_VARYING_INTERP_MODE_C4__SHIFT) & A3XX_VPC_VARYING_INTERP_MODE_C4__MASK;
+}
+#define A3XX_VPC_VARYING_INTERP_MODE_C5__MASK                  0x00000c00
+#define A3XX_VPC_VARYING_INTERP_MODE_C5__SHIFT                 10
+static inline uint32_t A3XX_VPC_VARYING_INTERP_MODE_C5(enum a3xx_intp_mode val)
+{
+       return ((val) << A3XX_VPC_VARYING_INTERP_MODE_C5__SHIFT) & A3XX_VPC_VARYING_INTERP_MODE_C5__MASK;
+}
+#define A3XX_VPC_VARYING_INTERP_MODE_C6__MASK                  0x00003000
+#define A3XX_VPC_VARYING_INTERP_MODE_C6__SHIFT                 12
+static inline uint32_t A3XX_VPC_VARYING_INTERP_MODE_C6(enum a3xx_intp_mode val)
+{
+       return ((val) << A3XX_VPC_VARYING_INTERP_MODE_C6__SHIFT) & A3XX_VPC_VARYING_INTERP_MODE_C6__MASK;
+}
+#define A3XX_VPC_VARYING_INTERP_MODE_C7__MASK                  0x0000c000
+#define A3XX_VPC_VARYING_INTERP_MODE_C7__SHIFT                 14
+static inline uint32_t A3XX_VPC_VARYING_INTERP_MODE_C7(enum a3xx_intp_mode val)
+{
+       return ((val) << A3XX_VPC_VARYING_INTERP_MODE_C7__SHIFT) & A3XX_VPC_VARYING_INTERP_MODE_C7__MASK;
+}
+#define A3XX_VPC_VARYING_INTERP_MODE_C8__MASK                  0x00030000
+#define A3XX_VPC_VARYING_INTERP_MODE_C8__SHIFT                 16
+static inline uint32_t A3XX_VPC_VARYING_INTERP_MODE_C8(enum a3xx_intp_mode val)
+{
+       return ((val) << A3XX_VPC_VARYING_INTERP_MODE_C8__SHIFT) & A3XX_VPC_VARYING_INTERP_MODE_C8__MASK;
+}
+#define A3XX_VPC_VARYING_INTERP_MODE_C9__MASK                  0x000c0000
+#define A3XX_VPC_VARYING_INTERP_MODE_C9__SHIFT                 18
+static inline uint32_t A3XX_VPC_VARYING_INTERP_MODE_C9(enum a3xx_intp_mode val)
+{
+       return ((val) << A3XX_VPC_VARYING_INTERP_MODE_C9__SHIFT) & A3XX_VPC_VARYING_INTERP_MODE_C9__MASK;
+}
+#define A3XX_VPC_VARYING_INTERP_MODE_CA__MASK                  0x00300000
+#define A3XX_VPC_VARYING_INTERP_MODE_CA__SHIFT                 20
+static inline uint32_t A3XX_VPC_VARYING_INTERP_MODE_CA(enum a3xx_intp_mode val)
+{
+       return ((val) << A3XX_VPC_VARYING_INTERP_MODE_CA__SHIFT) & A3XX_VPC_VARYING_INTERP_MODE_CA__MASK;
+}
+#define A3XX_VPC_VARYING_INTERP_MODE_CB__MASK                  0x00c00000
+#define A3XX_VPC_VARYING_INTERP_MODE_CB__SHIFT                 22
+static inline uint32_t A3XX_VPC_VARYING_INTERP_MODE_CB(enum a3xx_intp_mode val)
+{
+       return ((val) << A3XX_VPC_VARYING_INTERP_MODE_CB__SHIFT) & A3XX_VPC_VARYING_INTERP_MODE_CB__MASK;
+}
+#define A3XX_VPC_VARYING_INTERP_MODE_CC__MASK                  0x03000000
+#define A3XX_VPC_VARYING_INTERP_MODE_CC__SHIFT                 24
+static inline uint32_t A3XX_VPC_VARYING_INTERP_MODE_CC(enum a3xx_intp_mode val)
+{
+       return ((val) << A3XX_VPC_VARYING_INTERP_MODE_CC__SHIFT) & A3XX_VPC_VARYING_INTERP_MODE_CC__MASK;
+}
+#define A3XX_VPC_VARYING_INTERP_MODE_CD__MASK                  0x0c000000
+#define A3XX_VPC_VARYING_INTERP_MODE_CD__SHIFT                 26
+static inline uint32_t A3XX_VPC_VARYING_INTERP_MODE_CD(enum a3xx_intp_mode val)
+{
+       return ((val) << A3XX_VPC_VARYING_INTERP_MODE_CD__SHIFT) & A3XX_VPC_VARYING_INTERP_MODE_CD__MASK;
+}
+#define A3XX_VPC_VARYING_INTERP_MODE_CE__MASK                  0x30000000
+#define A3XX_VPC_VARYING_INTERP_MODE_CE__SHIFT                 28
+static inline uint32_t A3XX_VPC_VARYING_INTERP_MODE_CE(enum a3xx_intp_mode val)
+{
+       return ((val) << A3XX_VPC_VARYING_INTERP_MODE_CE__SHIFT) & A3XX_VPC_VARYING_INTERP_MODE_CE__MASK;
+}
+#define A3XX_VPC_VARYING_INTERP_MODE_CF__MASK                  0xc0000000
+#define A3XX_VPC_VARYING_INTERP_MODE_CF__SHIFT                 30
+static inline uint32_t A3XX_VPC_VARYING_INTERP_MODE_CF(enum a3xx_intp_mode val)
+{
+       return ((val) << A3XX_VPC_VARYING_INTERP_MODE_CF__SHIFT) & A3XX_VPC_VARYING_INTERP_MODE_CF__MASK;
+}
 
 static inline uint32_t REG_A3XX_VPC_VARYING_PS_REPL(uint32_t i0) { return 0x00002286 + 0x1*i0; }
 
@@ -1928,6 +2095,8 @@ static inline uint32_t A3XX_SP_FS_MRT_REG_REGID(uint32_t val)
        return ((val) << A3XX_SP_FS_MRT_REG_REGID__SHIFT) & A3XX_SP_FS_MRT_REG_REGID__MASK;
 }
 #define A3XX_SP_FS_MRT_REG_HALF_PRECISION                      0x00000100
+#define A3XX_SP_FS_MRT_REG_SINT                                        0x00000400
+#define A3XX_SP_FS_MRT_REG_UINT                                        0x00000800
 
 static inline uint32_t REG_A3XX_SP_FS_IMAGE_OUTPUT(uint32_t i0) { return 0x000022f4 + 0x1*i0; }
 
@@ -1947,6 +2116,8 @@ static inline uint32_t A3XX_SP_FS_LENGTH_REG_SHADERLENGTH(uint32_t val)
        return ((val) << A3XX_SP_FS_LENGTH_REG_SHADERLENGTH__SHIFT) & A3XX_SP_FS_LENGTH_REG_SHADERLENGTH__MASK;
 }
 
+#define REG_A3XX_PA_SC_AA_CONFIG                               0x00002301
+
 #define REG_A3XX_TPL1_TP_VS_TEX_OFFSET                         0x00002340
 #define A3XX_TPL1_TP_VS_TEX_OFFSET_SAMPLEROFFSET__MASK         0x000000ff
 #define A3XX_TPL1_TP_VS_TEX_OFFSET_SAMPLEROFFSET__SHIFT                0
@@ -2297,11 +2468,11 @@ static inline uint32_t A3XX_VGT_DRAW_INITIATOR_INDEX_SIZE(enum pc_di_index_size
 #define A3XX_VGT_DRAW_INITIATOR_NOT_EOP                                0x00001000
 #define A3XX_VGT_DRAW_INITIATOR_SMALL_INDEX                    0x00002000
 #define A3XX_VGT_DRAW_INITIATOR_PRE_DRAW_INITIATOR_ENABLE      0x00004000
-#define A3XX_VGT_DRAW_INITIATOR_NUM_INDICES__MASK              0xffff0000
-#define A3XX_VGT_DRAW_INITIATOR_NUM_INDICES__SHIFT             16
-static inline uint32_t A3XX_VGT_DRAW_INITIATOR_NUM_INDICES(uint32_t val)
+#define A3XX_VGT_DRAW_INITIATOR_NUM_INSTANCES__MASK            0xff000000
+#define A3XX_VGT_DRAW_INITIATOR_NUM_INSTANCES__SHIFT           24
+static inline uint32_t A3XX_VGT_DRAW_INITIATOR_NUM_INSTANCES(uint32_t val)
 {
-       return ((val) << A3XX_VGT_DRAW_INITIATOR_NUM_INDICES__SHIFT) & A3XX_VGT_DRAW_INITIATOR_NUM_INDICES__MASK;
+       return ((val) << A3XX_VGT_DRAW_INITIATOR_NUM_INSTANCES__SHIFT) & A3XX_VGT_DRAW_INITIATOR_NUM_INSTANCES__MASK;
 }
 
 #define REG_A3XX_VGT_IMMED_DATA                                        0x000021fd
@@ -2347,17 +2518,23 @@ static inline uint32_t A3XX_TEX_SAMP_0_COMPARE_FUNC(enum adreno_compare_func val
 #define A3XX_TEX_SAMP_0_UNNORM_COORDS                          0x80000000
 
 #define REG_A3XX_TEX_SAMP_1                                    0x00000001
+#define A3XX_TEX_SAMP_1_LOD_BIAS__MASK                         0x000007ff
+#define A3XX_TEX_SAMP_1_LOD_BIAS__SHIFT                                0
+static inline uint32_t A3XX_TEX_SAMP_1_LOD_BIAS(float val)
+{
+       return ((((int32_t)(val * 64.0))) << A3XX_TEX_SAMP_1_LOD_BIAS__SHIFT) & A3XX_TEX_SAMP_1_LOD_BIAS__MASK;
+}
 #define A3XX_TEX_SAMP_1_MAX_LOD__MASK                          0x003ff000
 #define A3XX_TEX_SAMP_1_MAX_LOD__SHIFT                         12
 static inline uint32_t A3XX_TEX_SAMP_1_MAX_LOD(float val)
 {
-       return ((((uint32_t)(val * 12.0))) << A3XX_TEX_SAMP_1_MAX_LOD__SHIFT) & A3XX_TEX_SAMP_1_MAX_LOD__MASK;
+       return ((((uint32_t)(val * 64.0))) << A3XX_TEX_SAMP_1_MAX_LOD__SHIFT) & A3XX_TEX_SAMP_1_MAX_LOD__MASK;
 }
 #define A3XX_TEX_SAMP_1_MIN_LOD__MASK                          0xffc00000
 #define A3XX_TEX_SAMP_1_MIN_LOD__SHIFT                         22
 static inline uint32_t A3XX_TEX_SAMP_1_MIN_LOD(float val)
 {
-       return ((((uint32_t)(val * 12.0))) << A3XX_TEX_SAMP_1_MIN_LOD__SHIFT) & A3XX_TEX_SAMP_1_MIN_LOD__MASK;
+       return ((((uint32_t)(val * 64.0))) << A3XX_TEX_SAMP_1_MIN_LOD__SHIFT) & A3XX_TEX_SAMP_1_MIN_LOD__MASK;
 }
 
 #define REG_A3XX_TEX_CONST_0                                   0x00000000
@@ -2448,6 +2625,24 @@ static inline uint32_t A3XX_TEX_CONST_2_SWAP(enum a3xx_color_swap val)
 }
 
 #define REG_A3XX_TEX_CONST_3                                   0x00000003
+#define A3XX_TEX_CONST_3_LAYERSZ1__MASK                                0x0000000f
+#define A3XX_TEX_CONST_3_LAYERSZ1__SHIFT                       0
+static inline uint32_t A3XX_TEX_CONST_3_LAYERSZ1(uint32_t val)
+{
+       return ((val >> 12) << A3XX_TEX_CONST_3_LAYERSZ1__SHIFT) & A3XX_TEX_CONST_3_LAYERSZ1__MASK;
+}
+#define A3XX_TEX_CONST_3_DEPTH__MASK                           0x0ffe0000
+#define A3XX_TEX_CONST_3_DEPTH__SHIFT                          17
+static inline uint32_t A3XX_TEX_CONST_3_DEPTH(uint32_t val)
+{
+       return ((val) << A3XX_TEX_CONST_3_DEPTH__SHIFT) & A3XX_TEX_CONST_3_DEPTH__MASK;
+}
+#define A3XX_TEX_CONST_3_LAYERSZ2__MASK                                0xf0000000
+#define A3XX_TEX_CONST_3_LAYERSZ2__SHIFT                       28
+static inline uint32_t A3XX_TEX_CONST_3_LAYERSZ2(uint32_t val)
+{
+       return ((val >> 12) << A3XX_TEX_CONST_3_LAYERSZ2__SHIFT) & A3XX_TEX_CONST_3_LAYERSZ2__MASK;
+}
 
 
 #endif /* A3XX_XML */
index 218c5b0603989b3474ef7815b91d6ec0371ab013..b66c53bdc039cafffd3be36a4fe39ccfb92fb470 100644 (file)
@@ -2,6 +2,8 @@
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
+ * Copyright (c) 2014 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.
@@ -406,6 +408,94 @@ static void a3xx_dump(struct msm_gpu *gpu)
                        gpu_read(gpu, REG_A3XX_RBBM_STATUS));
        adreno_dump(gpu);
 }
+/* Register offset defines for A3XX */
+static const unsigned int a3xx_register_offsets[REG_ADRENO_REGISTER_MAX] = {
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_DEBUG, REG_AXXX_CP_DEBUG),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_ME_RAM_WADDR, REG_AXXX_CP_ME_RAM_WADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_ME_RAM_DATA, REG_AXXX_CP_ME_RAM_DATA),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_PFP_UCODE_DATA,
+                       REG_A3XX_CP_PFP_UCODE_DATA),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_PFP_UCODE_ADDR,
+                       REG_A3XX_CP_PFP_UCODE_ADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_WFI_PEND_CTR, REG_A3XX_CP_WFI_PEND_CTR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE, REG_AXXX_CP_RB_BASE),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR_ADDR, REG_AXXX_CP_RB_RPTR_ADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR, REG_AXXX_CP_RB_RPTR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_WPTR, REG_AXXX_CP_RB_WPTR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_PROTECT_CTRL, REG_A3XX_CP_PROTECT_CTRL),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_ME_CNTL, REG_AXXX_CP_ME_CNTL),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_CNTL, REG_AXXX_CP_RB_CNTL),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_IB1_BASE, REG_AXXX_CP_IB1_BASE),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_IB1_BUFSZ, REG_AXXX_CP_IB1_BUFSZ),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_IB2_BASE, REG_AXXX_CP_IB2_BASE),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_IB2_BUFSZ, REG_AXXX_CP_IB2_BUFSZ),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_TIMESTAMP, REG_AXXX_CP_SCRATCH_REG0),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_ME_RAM_RADDR, REG_AXXX_CP_ME_RAM_RADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_SCRATCH_ADDR, REG_AXXX_SCRATCH_ADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_SCRATCH_UMSK, REG_AXXX_SCRATCH_UMSK),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_ROQ_ADDR, REG_A3XX_CP_ROQ_ADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_ROQ_DATA, REG_A3XX_CP_ROQ_DATA),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_MERCIU_ADDR, REG_A3XX_CP_MERCIU_ADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_MERCIU_DATA, REG_A3XX_CP_MERCIU_DATA),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_MERCIU_DATA2, REG_A3XX_CP_MERCIU_DATA2),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_MEQ_ADDR, REG_A3XX_CP_MEQ_ADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_MEQ_DATA, REG_A3XX_CP_MEQ_DATA),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_HW_FAULT, REG_A3XX_CP_HW_FAULT),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_PROTECT_STATUS,
+                       REG_A3XX_CP_PROTECT_STATUS),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_STATUS, REG_A3XX_RBBM_STATUS),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_CTL,
+                       REG_A3XX_RBBM_PERFCTR_CTL),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_CMD0,
+                       REG_A3XX_RBBM_PERFCTR_LOAD_CMD0),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_CMD1,
+                       REG_A3XX_RBBM_PERFCTR_LOAD_CMD1),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_PWR_1_LO,
+                       REG_A3XX_RBBM_PERFCTR_PWR_1_LO),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_INT_0_MASK, REG_A3XX_RBBM_INT_0_MASK),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_INT_0_STATUS,
+                       REG_A3XX_RBBM_INT_0_STATUS),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_AHB_ERROR_STATUS,
+                       REG_A3XX_RBBM_AHB_ERROR_STATUS),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_AHB_CMD, REG_A3XX_RBBM_AHB_CMD),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_INT_CLEAR_CMD,
+                       REG_A3XX_RBBM_INT_CLEAR_CMD),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_CLOCK_CTL, REG_A3XX_RBBM_CLOCK_CTL),
+       REG_ADRENO_DEFINE(REG_ADRENO_VPC_DEBUG_RAM_SEL,
+                       REG_A3XX_VPC_VPC_DEBUG_RAM_SEL),
+       REG_ADRENO_DEFINE(REG_ADRENO_VPC_DEBUG_RAM_READ,
+                       REG_A3XX_VPC_VPC_DEBUG_RAM_READ),
+       REG_ADRENO_DEFINE(REG_ADRENO_VSC_SIZE_ADDRESS,
+                       REG_A3XX_VSC_SIZE_ADDRESS),
+       REG_ADRENO_DEFINE(REG_ADRENO_VFD_CONTROL_0, REG_A3XX_VFD_CONTROL_0),
+       REG_ADRENO_DEFINE(REG_ADRENO_VFD_INDEX_MAX, REG_A3XX_VFD_INDEX_MAX),
+       REG_ADRENO_DEFINE(REG_ADRENO_SP_VS_PVT_MEM_ADDR_REG,
+                       REG_A3XX_SP_VS_PVT_MEM_ADDR_REG),
+       REG_ADRENO_DEFINE(REG_ADRENO_SP_FS_PVT_MEM_ADDR_REG,
+                       REG_A3XX_SP_FS_PVT_MEM_ADDR_REG),
+       REG_ADRENO_DEFINE(REG_ADRENO_SP_VS_OBJ_START_REG,
+                       REG_A3XX_SP_VS_OBJ_START_REG),
+       REG_ADRENO_DEFINE(REG_ADRENO_SP_FS_OBJ_START_REG,
+                       REG_A3XX_SP_FS_OBJ_START_REG),
+       REG_ADRENO_DEFINE(REG_ADRENO_PA_SC_AA_CONFIG, REG_A3XX_PA_SC_AA_CONFIG),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PM_OVERRIDE2,
+                       REG_A3XX_RBBM_PM_OVERRIDE2),
+       REG_ADRENO_DEFINE(REG_ADRENO_SCRATCH_REG2, REG_AXXX_CP_SCRATCH_REG2),
+       REG_ADRENO_DEFINE(REG_ADRENO_SQ_GPR_MANAGEMENT,
+                       REG_A3XX_SQ_GPR_MANAGEMENT),
+       REG_ADRENO_DEFINE(REG_ADRENO_SQ_INST_STORE_MANAGMENT,
+                       REG_A3XX_SQ_INST_STORE_MANAGMENT),
+       REG_ADRENO_DEFINE(REG_ADRENO_TP0_CHICKEN, REG_A3XX_TP0_CHICKEN),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_RBBM_CTL, REG_A3XX_RBBM_RBBM_CTL),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_SW_RESET_CMD,
+                       REG_A3XX_RBBM_SW_RESET_CMD),
+       REG_ADRENO_DEFINE(REG_ADRENO_UCHE_INVALIDATE0,
+                       REG_A3XX_UCHE_CACHE_INVALIDATE0_REG),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_VALUE_LO,
+                       REG_A3XX_RBBM_PERFCTR_LOAD_VALUE_LO),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_VALUE_HI,
+                       REG_A3XX_RBBM_PERFCTR_LOAD_VALUE_HI),
+};
 
 static const struct adreno_gpu_funcs funcs = {
        .base = {
@@ -463,6 +553,7 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
        gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
 
        adreno_gpu->registers = a3xx_registers;
+       adreno_gpu->reg_offsets = a3xx_register_offsets;
 
        ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs);
        if (ret)
diff --git a/drivers/gpu/drm/msm/adreno/a4xx.xml.h b/drivers/gpu/drm/msm/adreno/a4xx.xml.h
new file mode 100644 (file)
index 0000000..5a24c41
--- /dev/null
@@ -0,0 +1,2144 @@
+#ifndef A4XX_XML
+#define A4XX_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://github.com/freedreno/envytools/
+git clone https://github.com/freedreno/envytools.git
+
+The rules-ng-ng source files this header was generated from are:
+- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2014-11-13 22:44:30)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  15053 bytes, from 2014-11-09 15:45:47)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  63169 bytes, from 2014-11-13 22:44:18)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  49097 bytes, from 2014-11-14 15:38:00)
+
+Copyright (C) 2013-2014 by the following authors:
+- Rob Clark <robdclark@gmail.com> (robclark)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial
+portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+enum a4xx_color_fmt {
+       RB4_A8_UNORM = 1,
+       RB4_R5G6R5_UNORM = 14,
+       RB4_Z16_UNORM = 15,
+       RB4_R8G8B8_UNORM = 25,
+       RB4_R8G8B8A8_UNORM = 26,
+};
+
+enum a4xx_tile_mode {
+       TILE4_LINEAR = 0,
+       TILE4_3 = 3,
+};
+
+enum a4xx_rb_blend_opcode {
+       BLEND_DST_PLUS_SRC = 0,
+       BLEND_SRC_MINUS_DST = 1,
+       BLEND_DST_MINUS_SRC = 2,
+       BLEND_MIN_DST_SRC = 3,
+       BLEND_MAX_DST_SRC = 4,
+};
+
+enum a4xx_vtx_fmt {
+       VFMT4_FLOAT_32 = 1,
+       VFMT4_FLOAT_32_32 = 2,
+       VFMT4_FLOAT_32_32_32 = 3,
+       VFMT4_FLOAT_32_32_32_32 = 4,
+       VFMT4_FLOAT_16 = 5,
+       VFMT4_FLOAT_16_16 = 6,
+       VFMT4_FLOAT_16_16_16 = 7,
+       VFMT4_FLOAT_16_16_16_16 = 8,
+       VFMT4_FIXED_32 = 9,
+       VFMT4_FIXED_32_32 = 10,
+       VFMT4_FIXED_32_32_32 = 11,
+       VFMT4_FIXED_32_32_32_32 = 12,
+       VFMT4_SHORT_16 = 16,
+       VFMT4_SHORT_16_16 = 17,
+       VFMT4_SHORT_16_16_16 = 18,
+       VFMT4_SHORT_16_16_16_16 = 19,
+       VFMT4_USHORT_16 = 20,
+       VFMT4_USHORT_16_16 = 21,
+       VFMT4_USHORT_16_16_16 = 22,
+       VFMT4_USHORT_16_16_16_16 = 23,
+       VFMT4_NORM_SHORT_16 = 24,
+       VFMT4_NORM_SHORT_16_16 = 25,
+       VFMT4_NORM_SHORT_16_16_16 = 26,
+       VFMT4_NORM_SHORT_16_16_16_16 = 27,
+       VFMT4_NORM_USHORT_16 = 28,
+       VFMT4_NORM_USHORT_16_16 = 29,
+       VFMT4_NORM_USHORT_16_16_16 = 30,
+       VFMT4_NORM_USHORT_16_16_16_16 = 31,
+       VFMT4_UBYTE_8 = 40,
+       VFMT4_UBYTE_8_8 = 41,
+       VFMT4_UBYTE_8_8_8 = 42,
+       VFMT4_UBYTE_8_8_8_8 = 43,
+       VFMT4_NORM_UBYTE_8 = 44,
+       VFMT4_NORM_UBYTE_8_8 = 45,
+       VFMT4_NORM_UBYTE_8_8_8 = 46,
+       VFMT4_NORM_UBYTE_8_8_8_8 = 47,
+       VFMT4_BYTE_8 = 48,
+       VFMT4_BYTE_8_8 = 49,
+       VFMT4_BYTE_8_8_8 = 50,
+       VFMT4_BYTE_8_8_8_8 = 51,
+       VFMT4_NORM_BYTE_8 = 52,
+       VFMT4_NORM_BYTE_8_8 = 53,
+       VFMT4_NORM_BYTE_8_8_8 = 54,
+       VFMT4_NORM_BYTE_8_8_8_8 = 55,
+       VFMT4_UINT_10_10_10_2 = 60,
+       VFMT4_NORM_UINT_10_10_10_2 = 61,
+       VFMT4_INT_10_10_10_2 = 62,
+       VFMT4_NORM_INT_10_10_10_2 = 63,
+};
+
+enum a4xx_tex_fmt {
+       TFMT4_NORM_USHORT_565 = 11,
+       TFMT4_NORM_USHORT_5551 = 10,
+       TFMT4_NORM_USHORT_4444 = 8,
+       TFMT4_NORM_UINT_X8Z24 = 71,
+       TFMT4_NORM_UINT_2_10_10_10 = 33,
+       TFMT4_NORM_UINT_A8 = 3,
+       TFMT4_NORM_UINT_L8_A8 = 13,
+       TFMT4_NORM_UINT_8 = 4,
+       TFMT4_NORM_UINT_8_8_8_8 = 28,
+       TFMT4_FLOAT_16 = 20,
+       TFMT4_FLOAT_16_16 = 40,
+       TFMT4_FLOAT_16_16_16_16 = 53,
+       TFMT4_FLOAT_32 = 43,
+       TFMT4_FLOAT_32_32 = 56,
+       TFMT4_FLOAT_32_32_32_32 = 63,
+};
+
+enum a4xx_depth_format {
+       DEPTH4_NONE = 0,
+       DEPTH4_16 = 1,
+       DEPTH4_24_8 = 2,
+};
+
+enum a4xx_tex_filter {
+       A4XX_TEX_NEAREST = 0,
+       A4XX_TEX_LINEAR = 1,
+};
+
+enum a4xx_tex_clamp {
+       A4XX_TEX_REPEAT = 0,
+       A4XX_TEX_CLAMP_TO_EDGE = 1,
+       A4XX_TEX_MIRROR_REPEAT = 2,
+       A4XX_TEX_CLAMP_NONE = 3,
+};
+
+enum a4xx_tex_swiz {
+       A4XX_TEX_X = 0,
+       A4XX_TEX_Y = 1,
+       A4XX_TEX_Z = 2,
+       A4XX_TEX_W = 3,
+       A4XX_TEX_ZERO = 4,
+       A4XX_TEX_ONE = 5,
+};
+
+enum a4xx_tex_type {
+       A4XX_TEX_1D = 0,
+       A4XX_TEX_2D = 1,
+       A4XX_TEX_CUBE = 2,
+       A4XX_TEX_3D = 3,
+};
+
+#define A4XX_CGC_HLSQ_EARLY_CYC__MASK                          0x00700000
+#define A4XX_CGC_HLSQ_EARLY_CYC__SHIFT                         20
+static inline uint32_t A4XX_CGC_HLSQ_EARLY_CYC(uint32_t val)
+{
+       return ((val) << A4XX_CGC_HLSQ_EARLY_CYC__SHIFT) & A4XX_CGC_HLSQ_EARLY_CYC__MASK;
+}
+#define A4XX_INT0_RBBM_GPU_IDLE                                        0x00000001
+#define A4XX_INT0_RBBM_AHB_ERROR                               0x00000002
+#define A4XX_INT0_RBBM_REG_TIMEOUT                             0x00000004
+#define A4XX_INT0_RBBM_ME_MS_TIMEOUT                           0x00000008
+#define A4XX_INT0_RBBM_PFP_MS_TIMEOUT                          0x00000010
+#define A4XX_INT0_RBBM_ATB_BUS_OVERFLOW                                0x00000020
+#define A4XX_INT0_VFD_ERROR                                    0x00000040
+#define A4XX_INT0_CP_SW_INT                                    0x00000080
+#define A4XX_INT0_CP_T0_PACKET_IN_IB                           0x00000100
+#define A4XX_INT0_CP_OPCODE_ERROR                              0x00000200
+#define A4XX_INT0_CP_RESERVED_BIT_ERROR                                0x00000400
+#define A4XX_INT0_CP_HW_FAULT                                  0x00000800
+#define A4XX_INT0_CP_DMA                                       0x00001000
+#define A4XX_INT0_CP_IB2_INT                                   0x00002000
+#define A4XX_INT0_CP_IB1_INT                                   0x00004000
+#define A4XX_INT0_CP_RB_INT                                    0x00008000
+#define A4XX_INT0_CP_REG_PROTECT_FAULT                         0x00010000
+#define A4XX_INT0_CP_RB_DONE_TS                                        0x00020000
+#define A4XX_INT0_CP_VS_DONE_TS                                        0x00040000
+#define A4XX_INT0_CP_PS_DONE_TS                                        0x00080000
+#define A4XX_INT0_CACHE_FLUSH_TS                               0x00100000
+#define A4XX_INT0_CP_AHB_ERROR_HALT                            0x00200000
+#define A4XX_INT0_MISC_HANG_DETECT                             0x01000000
+#define A4XX_INT0_UCHE_OOB_ACCESS                              0x02000000
+#define REG_A4XX_RB_GMEM_BASE_ADDR                             0x00000cc0
+
+#define REG_A4XX_RB_PERFCTR_RB_SEL_0                           0x00000cc7
+
+#define REG_A4XX_RB_PERFCTR_RB_SEL_1                           0x00000cc8
+
+#define REG_A4XX_RB_PERFCTR_RB_SEL_2                           0x00000cc9
+
+#define REG_A4XX_RB_PERFCTR_RB_SEL_3                           0x00000cca
+
+#define REG_A4XX_RB_PERFCTR_RB_SEL_4                           0x00000ccb
+
+#define REG_A4XX_RB_PERFCTR_RB_SEL_5                           0x00000ccc
+
+#define REG_A4XX_RB_PERFCTR_RB_SEL_6                           0x00000ccd
+
+#define REG_A4XX_RB_PERFCTR_RB_SEL_7                           0x00000cce
+
+#define REG_A4XX_RB_PERFCTR_CCU_SEL_3                          0x00000cd2
+
+#define REG_A4XX_RB_FRAME_BUFFER_DIMENSION                     0x00000ce0
+#define A4XX_RB_FRAME_BUFFER_DIMENSION_WIDTH__MASK             0x00003fff
+#define A4XX_RB_FRAME_BUFFER_DIMENSION_WIDTH__SHIFT            0
+static inline uint32_t A4XX_RB_FRAME_BUFFER_DIMENSION_WIDTH(uint32_t val)
+{
+       return ((val) << A4XX_RB_FRAME_BUFFER_DIMENSION_WIDTH__SHIFT) & A4XX_RB_FRAME_BUFFER_DIMENSION_WIDTH__MASK;
+}
+#define A4XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT__MASK            0x3fff0000
+#define A4XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT__SHIFT           16
+static inline uint32_t A4XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT(uint32_t val)
+{
+       return ((val) << A4XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT__SHIFT) & A4XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT__MASK;
+}
+
+#define REG_A4XX_RB_CLEAR_COLOR_DW0                            0x000020cc
+
+#define REG_A4XX_RB_CLEAR_COLOR_DW1                            0x000020cd
+
+#define REG_A4XX_RB_CLEAR_COLOR_DW2                            0x000020ce
+
+#define REG_A4XX_RB_CLEAR_COLOR_DW3                            0x000020cf
+
+#define REG_A4XX_RB_MODE_CONTROL                               0x000020a0
+#define A4XX_RB_MODE_CONTROL_WIDTH__MASK                       0x0000003f
+#define A4XX_RB_MODE_CONTROL_WIDTH__SHIFT                      0
+static inline uint32_t A4XX_RB_MODE_CONTROL_WIDTH(uint32_t val)
+{
+       return ((val >> 5) << A4XX_RB_MODE_CONTROL_WIDTH__SHIFT) & A4XX_RB_MODE_CONTROL_WIDTH__MASK;
+}
+#define A4XX_RB_MODE_CONTROL_HEIGHT__MASK                      0x00003f00
+#define A4XX_RB_MODE_CONTROL_HEIGHT__SHIFT                     8
+static inline uint32_t A4XX_RB_MODE_CONTROL_HEIGHT(uint32_t val)
+{
+       return ((val >> 5) << A4XX_RB_MODE_CONTROL_HEIGHT__SHIFT) & A4XX_RB_MODE_CONTROL_HEIGHT__MASK;
+}
+
+#define REG_A4XX_RB_RENDER_CONTROL                             0x000020a1
+#define A4XX_RB_RENDER_CONTROL_BINNING_PASS                    0x00000001
+#define A4XX_RB_RENDER_CONTROL_DISABLE_COLOR_PIPE              0x00000020
+
+#define REG_A4XX_RB_MSAA_CONTROL                               0x000020a2
+#define A4XX_RB_MSAA_CONTROL_DISABLE                           0x00001000
+#define A4XX_RB_MSAA_CONTROL_SAMPLES__MASK                     0x0000e000
+#define A4XX_RB_MSAA_CONTROL_SAMPLES__SHIFT                    13
+static inline uint32_t A4XX_RB_MSAA_CONTROL_SAMPLES(uint32_t val)
+{
+       return ((val) << A4XX_RB_MSAA_CONTROL_SAMPLES__SHIFT) & A4XX_RB_MSAA_CONTROL_SAMPLES__MASK;
+}
+
+#define REG_A4XX_RB_MSAA_CONTROL2                              0x000020a3
+#define A4XX_RB_MSAA_CONTROL2_MSAA_SAMPLES__MASK               0x00000380
+#define A4XX_RB_MSAA_CONTROL2_MSAA_SAMPLES__SHIFT              7
+static inline uint32_t A4XX_RB_MSAA_CONTROL2_MSAA_SAMPLES(uint32_t val)
+{
+       return ((val) << A4XX_RB_MSAA_CONTROL2_MSAA_SAMPLES__SHIFT) & A4XX_RB_MSAA_CONTROL2_MSAA_SAMPLES__MASK;
+}
+#define A4XX_RB_MSAA_CONTROL2_VARYING                          0x00001000
+
+static inline uint32_t REG_A4XX_RB_MRT(uint32_t i0) { return 0x000020a4 + 0x5*i0; }
+
+static inline uint32_t REG_A4XX_RB_MRT_CONTROL(uint32_t i0) { return 0x000020a4 + 0x5*i0; }
+#define A4XX_RB_MRT_CONTROL_READ_DEST_ENABLE                   0x00000008
+#define A4XX_RB_MRT_CONTROL_BLEND                              0x00000010
+#define A4XX_RB_MRT_CONTROL_BLEND2                             0x00000020
+#define A4XX_RB_MRT_CONTROL_FASTCLEAR                          0x00000400
+#define A4XX_RB_MRT_CONTROL_B11                                        0x00000800
+#define A4XX_RB_MRT_CONTROL_COMPONENT_ENABLE__MASK             0x0f000000
+#define A4XX_RB_MRT_CONTROL_COMPONENT_ENABLE__SHIFT            24
+static inline uint32_t A4XX_RB_MRT_CONTROL_COMPONENT_ENABLE(uint32_t val)
+{
+       return ((val) << A4XX_RB_MRT_CONTROL_COMPONENT_ENABLE__SHIFT) & A4XX_RB_MRT_CONTROL_COMPONENT_ENABLE__MASK;
+}
+
+static inline uint32_t REG_A4XX_RB_MRT_BUF_INFO(uint32_t i0) { return 0x000020a5 + 0x5*i0; }
+#define A4XX_RB_MRT_BUF_INFO_COLOR_FORMAT__MASK                        0x0000003f
+#define A4XX_RB_MRT_BUF_INFO_COLOR_FORMAT__SHIFT               0
+static inline uint32_t A4XX_RB_MRT_BUF_INFO_COLOR_FORMAT(enum a4xx_color_fmt val)
+{
+       return ((val) << A4XX_RB_MRT_BUF_INFO_COLOR_FORMAT__SHIFT) & A4XX_RB_MRT_BUF_INFO_COLOR_FORMAT__MASK;
+}
+#define A4XX_RB_MRT_BUF_INFO_DITHER_MODE__MASK                 0x00000600
+#define A4XX_RB_MRT_BUF_INFO_DITHER_MODE__SHIFT                        9
+static inline uint32_t A4XX_RB_MRT_BUF_INFO_DITHER_MODE(enum adreno_rb_dither_mode val)
+{
+       return ((val) << A4XX_RB_MRT_BUF_INFO_DITHER_MODE__SHIFT) & A4XX_RB_MRT_BUF_INFO_DITHER_MODE__MASK;
+}
+#define A4XX_RB_MRT_BUF_INFO_COLOR_SWAP__MASK                  0x00001800
+#define A4XX_RB_MRT_BUF_INFO_COLOR_SWAP__SHIFT                 11
+static inline uint32_t A4XX_RB_MRT_BUF_INFO_COLOR_SWAP(enum a3xx_color_swap val)
+{
+       return ((val) << A4XX_RB_MRT_BUF_INFO_COLOR_SWAP__SHIFT) & A4XX_RB_MRT_BUF_INFO_COLOR_SWAP__MASK;
+}
+#define A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__MASK             0x007fc000
+#define A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__SHIFT            14
+static inline uint32_t A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH(uint32_t val)
+{
+       return ((val >> 4) << A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__SHIFT) & A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__MASK;
+}
+
+static inline uint32_t REG_A4XX_RB_MRT_BASE(uint32_t i0) { return 0x000020a6 + 0x5*i0; }
+
+static inline uint32_t REG_A4XX_RB_MRT_CONTROL3(uint32_t i0) { return 0x000020a7 + 0x5*i0; }
+#define A4XX_RB_MRT_CONTROL3_STRIDE__MASK                      0x0001fff8
+#define A4XX_RB_MRT_CONTROL3_STRIDE__SHIFT                     3
+static inline uint32_t A4XX_RB_MRT_CONTROL3_STRIDE(uint32_t val)
+{
+       return ((val) << A4XX_RB_MRT_CONTROL3_STRIDE__SHIFT) & A4XX_RB_MRT_CONTROL3_STRIDE__MASK;
+}
+
+static inline uint32_t REG_A4XX_RB_MRT_BLEND_CONTROL(uint32_t i0) { return 0x000020a8 + 0x5*i0; }
+#define A4XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR__MASK         0x0000001f
+#define A4XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR__SHIFT                0
+static inline uint32_t A4XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR(enum adreno_rb_blend_factor val)
+{
+       return ((val) << A4XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR__SHIFT) & A4XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR__MASK;
+}
+#define A4XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__MASK       0x000000e0
+#define A4XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__SHIFT      5
+static inline uint32_t A4XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE(enum a4xx_rb_blend_opcode val)
+{
+       return ((val) << A4XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__SHIFT) & A4XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__MASK;
+}
+#define A4XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR__MASK                0x00001f00
+#define A4XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR__SHIFT       8
+static inline uint32_t A4XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR(enum adreno_rb_blend_factor val)
+{
+       return ((val) << A4XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR__SHIFT) & A4XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR__MASK;
+}
+#define A4XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR__MASK       0x001f0000
+#define A4XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR__SHIFT      16
+static inline uint32_t A4XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR(enum adreno_rb_blend_factor val)
+{
+       return ((val) << A4XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR__SHIFT) & A4XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR__MASK;
+}
+#define A4XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__MASK     0x00e00000
+#define A4XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__SHIFT    21
+static inline uint32_t A4XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE(enum a4xx_rb_blend_opcode val)
+{
+       return ((val) << A4XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__SHIFT) & A4XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__MASK;
+}
+#define A4XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__MASK      0x1f000000
+#define A4XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__SHIFT     24
+static inline uint32_t A4XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR(enum adreno_rb_blend_factor val)
+{
+       return ((val) << A4XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__SHIFT) & A4XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__MASK;
+}
+
+#define REG_A4XX_RB_ALPHA_CONTROL                              0x000020f8
+#define A4XX_RB_ALPHA_CONTROL_ALPHA_TEST                       0x00000100
+#define A4XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC__MASK            0x00000e00
+#define A4XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC__SHIFT           9
+static inline uint32_t A4XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC(enum adreno_compare_func val)
+{
+       return ((val) << A4XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC__SHIFT) & A4XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC__MASK;
+}
+
+#define REG_A4XX_RB_FS_OUTPUT                                  0x000020f9
+#define A4XX_RB_FS_OUTPUT_ENABLE_COLOR_PIPE                    0x00000001
+#define A4XX_RB_FS_OUTPUT_FAST_CLEAR                           0x00000100
+#define A4XX_RB_FS_OUTPUT_SAMPLE_MASK__MASK                    0xffff0000
+#define A4XX_RB_FS_OUTPUT_SAMPLE_MASK__SHIFT                   16
+static inline uint32_t A4XX_RB_FS_OUTPUT_SAMPLE_MASK(uint32_t val)
+{
+       return ((val) << A4XX_RB_FS_OUTPUT_SAMPLE_MASK__SHIFT) & A4XX_RB_FS_OUTPUT_SAMPLE_MASK__MASK;
+}
+
+#define REG_A4XX_RB_RENDER_CONTROL3                            0x000020fb
+#define A4XX_RB_RENDER_CONTROL3_COMPONENT_ENABLE__MASK         0x0000001f
+#define A4XX_RB_RENDER_CONTROL3_COMPONENT_ENABLE__SHIFT                0
+static inline uint32_t A4XX_RB_RENDER_CONTROL3_COMPONENT_ENABLE(uint32_t val)
+{
+       return ((val) << A4XX_RB_RENDER_CONTROL3_COMPONENT_ENABLE__SHIFT) & A4XX_RB_RENDER_CONTROL3_COMPONENT_ENABLE__MASK;
+}
+
+#define REG_A4XX_RB_COPY_CONTROL                               0x000020fc
+#define A4XX_RB_COPY_CONTROL_MSAA_RESOLVE__MASK                        0x00000003
+#define A4XX_RB_COPY_CONTROL_MSAA_RESOLVE__SHIFT               0
+static inline uint32_t A4XX_RB_COPY_CONTROL_MSAA_RESOLVE(enum a3xx_msaa_samples val)
+{
+       return ((val) << A4XX_RB_COPY_CONTROL_MSAA_RESOLVE__SHIFT) & A4XX_RB_COPY_CONTROL_MSAA_RESOLVE__MASK;
+}
+#define A4XX_RB_COPY_CONTROL_MODE__MASK                                0x00000070
+#define A4XX_RB_COPY_CONTROL_MODE__SHIFT                       4
+static inline uint32_t A4XX_RB_COPY_CONTROL_MODE(enum adreno_rb_copy_control_mode val)
+{
+       return ((val) << A4XX_RB_COPY_CONTROL_MODE__SHIFT) & A4XX_RB_COPY_CONTROL_MODE__MASK;
+}
+#define A4XX_RB_COPY_CONTROL_FASTCLEAR__MASK                   0x00000f00
+#define A4XX_RB_COPY_CONTROL_FASTCLEAR__SHIFT                  8
+static inline uint32_t A4XX_RB_COPY_CONTROL_FASTCLEAR(uint32_t val)
+{
+       return ((val) << A4XX_RB_COPY_CONTROL_FASTCLEAR__SHIFT) & A4XX_RB_COPY_CONTROL_FASTCLEAR__MASK;
+}
+#define A4XX_RB_COPY_CONTROL_GMEM_BASE__MASK                   0xffffc000
+#define A4XX_RB_COPY_CONTROL_GMEM_BASE__SHIFT                  14
+static inline uint32_t A4XX_RB_COPY_CONTROL_GMEM_BASE(uint32_t val)
+{
+       return ((val >> 14) << A4XX_RB_COPY_CONTROL_GMEM_BASE__SHIFT) & A4XX_RB_COPY_CONTROL_GMEM_BASE__MASK;
+}
+
+#define REG_A4XX_RB_COPY_DEST_BASE                             0x000020fd
+#define A4XX_RB_COPY_DEST_BASE_BASE__MASK                      0xfffffff0
+#define A4XX_RB_COPY_DEST_BASE_BASE__SHIFT                     4
+static inline uint32_t A4XX_RB_COPY_DEST_BASE_BASE(uint32_t val)
+{
+       return ((val >> 4) << A4XX_RB_COPY_DEST_BASE_BASE__SHIFT) & A4XX_RB_COPY_DEST_BASE_BASE__MASK;
+}
+
+#define REG_A4XX_RB_COPY_DEST_PITCH                            0x000020fe
+#define A4XX_RB_COPY_DEST_PITCH_PITCH__MASK                    0xffffffff
+#define A4XX_RB_COPY_DEST_PITCH_PITCH__SHIFT                   0
+static inline uint32_t A4XX_RB_COPY_DEST_PITCH_PITCH(uint32_t val)
+{
+       return ((val >> 5) << A4XX_RB_COPY_DEST_PITCH_PITCH__SHIFT) & A4XX_RB_COPY_DEST_PITCH_PITCH__MASK;
+}
+
+#define REG_A4XX_RB_COPY_DEST_INFO                             0x000020ff
+#define A4XX_RB_COPY_DEST_INFO_FORMAT__MASK                    0x000000fc
+#define A4XX_RB_COPY_DEST_INFO_FORMAT__SHIFT                   2
+static inline uint32_t A4XX_RB_COPY_DEST_INFO_FORMAT(enum a4xx_color_fmt val)
+{
+       return ((val) << A4XX_RB_COPY_DEST_INFO_FORMAT__SHIFT) & A4XX_RB_COPY_DEST_INFO_FORMAT__MASK;
+}
+#define A4XX_RB_COPY_DEST_INFO_SWAP__MASK                      0x00000300
+#define A4XX_RB_COPY_DEST_INFO_SWAP__SHIFT                     8
+static inline uint32_t A4XX_RB_COPY_DEST_INFO_SWAP(enum a3xx_color_swap val)
+{
+       return ((val) << A4XX_RB_COPY_DEST_INFO_SWAP__SHIFT) & A4XX_RB_COPY_DEST_INFO_SWAP__MASK;
+}
+#define A4XX_RB_COPY_DEST_INFO_DITHER_MODE__MASK               0x00000c00
+#define A4XX_RB_COPY_DEST_INFO_DITHER_MODE__SHIFT              10
+static inline uint32_t A4XX_RB_COPY_DEST_INFO_DITHER_MODE(enum adreno_rb_dither_mode val)
+{
+       return ((val) << A4XX_RB_COPY_DEST_INFO_DITHER_MODE__SHIFT) & A4XX_RB_COPY_DEST_INFO_DITHER_MODE__MASK;
+}
+#define A4XX_RB_COPY_DEST_INFO_COMPONENT_ENABLE__MASK          0x0003c000
+#define A4XX_RB_COPY_DEST_INFO_COMPONENT_ENABLE__SHIFT         14
+static inline uint32_t A4XX_RB_COPY_DEST_INFO_COMPONENT_ENABLE(uint32_t val)
+{
+       return ((val) << A4XX_RB_COPY_DEST_INFO_COMPONENT_ENABLE__SHIFT) & A4XX_RB_COPY_DEST_INFO_COMPONENT_ENABLE__MASK;
+}
+#define A4XX_RB_COPY_DEST_INFO_ENDIAN__MASK                    0x001c0000
+#define A4XX_RB_COPY_DEST_INFO_ENDIAN__SHIFT                   18
+static inline uint32_t A4XX_RB_COPY_DEST_INFO_ENDIAN(enum adreno_rb_surface_endian val)
+{
+       return ((val) << A4XX_RB_COPY_DEST_INFO_ENDIAN__SHIFT) & A4XX_RB_COPY_DEST_INFO_ENDIAN__MASK;
+}
+#define A4XX_RB_COPY_DEST_INFO_TILE__MASK                      0x03000000
+#define A4XX_RB_COPY_DEST_INFO_TILE__SHIFT                     24
+static inline uint32_t A4XX_RB_COPY_DEST_INFO_TILE(enum a4xx_tile_mode val)
+{
+       return ((val) << A4XX_RB_COPY_DEST_INFO_TILE__SHIFT) & A4XX_RB_COPY_DEST_INFO_TILE__MASK;
+}
+
+#define REG_A4XX_RB_FS_OUTPUT_REG                              0x00002100
+#define A4XX_RB_FS_OUTPUT_REG_COLOR_PIPE_ENABLE                        0x00000001
+#define A4XX_RB_FS_OUTPUT_REG_FRAG_WRITES_Z                    0x00000020
+
+#define REG_A4XX_RB_DEPTH_CONTROL                              0x00002101
+#define A4XX_RB_DEPTH_CONTROL_FRAG_WRITES_Z                    0x00000001
+#define A4XX_RB_DEPTH_CONTROL_Z_ENABLE                         0x00000002
+#define A4XX_RB_DEPTH_CONTROL_Z_WRITE_ENABLE                   0x00000004
+#define A4XX_RB_DEPTH_CONTROL_ZFUNC__MASK                      0x00000070
+#define A4XX_RB_DEPTH_CONTROL_ZFUNC__SHIFT                     4
+static inline uint32_t A4XX_RB_DEPTH_CONTROL_ZFUNC(enum adreno_compare_func val)
+{
+       return ((val) << A4XX_RB_DEPTH_CONTROL_ZFUNC__SHIFT) & A4XX_RB_DEPTH_CONTROL_ZFUNC__MASK;
+}
+#define A4XX_RB_DEPTH_CONTROL_BF_ENABLE                                0x00000080
+#define A4XX_RB_DEPTH_CONTROL_EARLY_Z_DISABLE                  0x00010000
+#define A4XX_RB_DEPTH_CONTROL_Z_TEST_ENABLE                    0x80000000
+
+#define REG_A4XX_RB_DEPTH_CLEAR                                        0x00002102
+
+#define REG_A4XX_RB_DEPTH_INFO                                 0x00002103
+#define A4XX_RB_DEPTH_INFO_DEPTH_FORMAT__MASK                  0x00000003
+#define A4XX_RB_DEPTH_INFO_DEPTH_FORMAT__SHIFT                 0
+static inline uint32_t A4XX_RB_DEPTH_INFO_DEPTH_FORMAT(enum a4xx_depth_format val)
+{
+       return ((val) << A4XX_RB_DEPTH_INFO_DEPTH_FORMAT__SHIFT) & A4XX_RB_DEPTH_INFO_DEPTH_FORMAT__MASK;
+}
+#define A4XX_RB_DEPTH_INFO_DEPTH_BASE__MASK                    0xfffff000
+#define A4XX_RB_DEPTH_INFO_DEPTH_BASE__SHIFT                   12
+static inline uint32_t A4XX_RB_DEPTH_INFO_DEPTH_BASE(uint32_t val)
+{
+       return ((val >> 12) << A4XX_RB_DEPTH_INFO_DEPTH_BASE__SHIFT) & A4XX_RB_DEPTH_INFO_DEPTH_BASE__MASK;
+}
+
+#define REG_A4XX_RB_DEPTH_PITCH                                        0x00002104
+#define A4XX_RB_DEPTH_PITCH__MASK                              0xffffffff
+#define A4XX_RB_DEPTH_PITCH__SHIFT                             0
+static inline uint32_t A4XX_RB_DEPTH_PITCH(uint32_t val)
+{
+       return ((val >> 4) << A4XX_RB_DEPTH_PITCH__SHIFT) & A4XX_RB_DEPTH_PITCH__MASK;
+}
+
+#define REG_A4XX_RB_DEPTH_PITCH2                               0x00002105
+#define A4XX_RB_DEPTH_PITCH2__MASK                             0xffffffff
+#define A4XX_RB_DEPTH_PITCH2__SHIFT                            0
+static inline uint32_t A4XX_RB_DEPTH_PITCH2(uint32_t val)
+{
+       return ((val >> 4) << A4XX_RB_DEPTH_PITCH2__SHIFT) & A4XX_RB_DEPTH_PITCH2__MASK;
+}
+
+#define REG_A4XX_RB_STENCIL_CONTROL                            0x00002106
+#define A4XX_RB_STENCIL_CONTROL_STENCIL_ENABLE                 0x00000001
+#define A4XX_RB_STENCIL_CONTROL_STENCIL_ENABLE_BF              0x00000002
+#define A4XX_RB_STENCIL_CONTROL_STENCIL_READ                   0x00000004
+#define A4XX_RB_STENCIL_CONTROL_FUNC__MASK                     0x00000700
+#define A4XX_RB_STENCIL_CONTROL_FUNC__SHIFT                    8
+static inline uint32_t A4XX_RB_STENCIL_CONTROL_FUNC(enum adreno_compare_func val)
+{
+       return ((val) << A4XX_RB_STENCIL_CONTROL_FUNC__SHIFT) & A4XX_RB_STENCIL_CONTROL_FUNC__MASK;
+}
+#define A4XX_RB_STENCIL_CONTROL_FAIL__MASK                     0x00003800
+#define A4XX_RB_STENCIL_CONTROL_FAIL__SHIFT                    11
+static inline uint32_t A4XX_RB_STENCIL_CONTROL_FAIL(enum adreno_stencil_op val)
+{
+       return ((val) << A4XX_RB_STENCIL_CONTROL_FAIL__SHIFT) & A4XX_RB_STENCIL_CONTROL_FAIL__MASK;
+}
+#define A4XX_RB_STENCIL_CONTROL_ZPASS__MASK                    0x0001c000
+#define A4XX_RB_STENCIL_CONTROL_ZPASS__SHIFT                   14
+static inline uint32_t A4XX_RB_STENCIL_CONTROL_ZPASS(enum adreno_stencil_op val)
+{
+       return ((val) << A4XX_RB_STENCIL_CONTROL_ZPASS__SHIFT) & A4XX_RB_STENCIL_CONTROL_ZPASS__MASK;
+}
+#define A4XX_RB_STENCIL_CONTROL_ZFAIL__MASK                    0x000e0000
+#define A4XX_RB_STENCIL_CONTROL_ZFAIL__SHIFT                   17
+static inline uint32_t A4XX_RB_STENCIL_CONTROL_ZFAIL(enum adreno_stencil_op val)
+{
+       return ((val) << A4XX_RB_STENCIL_CONTROL_ZFAIL__SHIFT) & A4XX_RB_STENCIL_CONTROL_ZFAIL__MASK;
+}
+#define A4XX_RB_STENCIL_CONTROL_FUNC_BF__MASK                  0x00700000
+#define A4XX_RB_STENCIL_CONTROL_FUNC_BF__SHIFT                 20
+static inline uint32_t A4XX_RB_STENCIL_CONTROL_FUNC_BF(enum adreno_compare_func val)
+{
+       return ((val) << A4XX_RB_STENCIL_CONTROL_FUNC_BF__SHIFT) & A4XX_RB_STENCIL_CONTROL_FUNC_BF__MASK;
+}
+#define A4XX_RB_STENCIL_CONTROL_FAIL_BF__MASK                  0x03800000
+#define A4XX_RB_STENCIL_CONTROL_FAIL_BF__SHIFT                 23
+static inline uint32_t A4XX_RB_STENCIL_CONTROL_FAIL_BF(enum adreno_stencil_op val)
+{
+       return ((val) << A4XX_RB_STENCIL_CONTROL_FAIL_BF__SHIFT) & A4XX_RB_STENCIL_CONTROL_FAIL_BF__MASK;
+}
+#define A4XX_RB_STENCIL_CONTROL_ZPASS_BF__MASK                 0x1c000000
+#define A4XX_RB_STENCIL_CONTROL_ZPASS_BF__SHIFT                        26
+static inline uint32_t A4XX_RB_STENCIL_CONTROL_ZPASS_BF(enum adreno_stencil_op val)
+{
+       return ((val) << A4XX_RB_STENCIL_CONTROL_ZPASS_BF__SHIFT) & A4XX_RB_STENCIL_CONTROL_ZPASS_BF__MASK;
+}
+#define A4XX_RB_STENCIL_CONTROL_ZFAIL_BF__MASK                 0xe0000000
+#define A4XX_RB_STENCIL_CONTROL_ZFAIL_BF__SHIFT                        29
+static inline uint32_t A4XX_RB_STENCIL_CONTROL_ZFAIL_BF(enum adreno_stencil_op val)
+{
+       return ((val) << A4XX_RB_STENCIL_CONTROL_ZFAIL_BF__SHIFT) & A4XX_RB_STENCIL_CONTROL_ZFAIL_BF__MASK;
+}
+
+#define REG_A4XX_RB_STENCIL_CONTROL2                           0x00002107
+#define A4XX_RB_STENCIL_CONTROL2_STENCIL_BUFFER                        0x00000001
+
+#define REG_A4XX_RB_STENCILREFMASK                             0x0000210b
+#define A4XX_RB_STENCILREFMASK_STENCILREF__MASK                        0x000000ff
+#define A4XX_RB_STENCILREFMASK_STENCILREF__SHIFT               0
+static inline uint32_t A4XX_RB_STENCILREFMASK_STENCILREF(uint32_t val)
+{
+       return ((val) << A4XX_RB_STENCILREFMASK_STENCILREF__SHIFT) & A4XX_RB_STENCILREFMASK_STENCILREF__MASK;
+}
+#define A4XX_RB_STENCILREFMASK_STENCILMASK__MASK               0x0000ff00
+#define A4XX_RB_STENCILREFMASK_STENCILMASK__SHIFT              8
+static inline uint32_t A4XX_RB_STENCILREFMASK_STENCILMASK(uint32_t val)
+{
+       return ((val) << A4XX_RB_STENCILREFMASK_STENCILMASK__SHIFT) & A4XX_RB_STENCILREFMASK_STENCILMASK__MASK;
+}
+#define A4XX_RB_STENCILREFMASK_STENCILWRITEMASK__MASK          0x00ff0000
+#define A4XX_RB_STENCILREFMASK_STENCILWRITEMASK__SHIFT         16
+static inline uint32_t A4XX_RB_STENCILREFMASK_STENCILWRITEMASK(uint32_t val)
+{
+       return ((val) << A4XX_RB_STENCILREFMASK_STENCILWRITEMASK__SHIFT) & A4XX_RB_STENCILREFMASK_STENCILWRITEMASK__MASK;
+}
+
+#define REG_A4XX_RB_STENCILREFMASK_BF                          0x0000210c
+#define A4XX_RB_STENCILREFMASK_BF_STENCILREF__MASK             0x000000ff
+#define A4XX_RB_STENCILREFMASK_BF_STENCILREF__SHIFT            0
+static inline uint32_t A4XX_RB_STENCILREFMASK_BF_STENCILREF(uint32_t val)
+{
+       return ((val) << A4XX_RB_STENCILREFMASK_BF_STENCILREF__SHIFT) & A4XX_RB_STENCILREFMASK_BF_STENCILREF__MASK;
+}
+#define A4XX_RB_STENCILREFMASK_BF_STENCILMASK__MASK            0x0000ff00
+#define A4XX_RB_STENCILREFMASK_BF_STENCILMASK__SHIFT           8
+static inline uint32_t A4XX_RB_STENCILREFMASK_BF_STENCILMASK(uint32_t val)
+{
+       return ((val) << A4XX_RB_STENCILREFMASK_BF_STENCILMASK__SHIFT) & A4XX_RB_STENCILREFMASK_BF_STENCILMASK__MASK;
+}
+#define A4XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__MASK       0x00ff0000
+#define A4XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__SHIFT      16
+static inline uint32_t A4XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK(uint32_t val)
+{
+       return ((val) << A4XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__SHIFT) & A4XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__MASK;
+}
+
+#define REG_A4XX_RB_BIN_OFFSET                                 0x0000210d
+#define A4XX_RB_BIN_OFFSET_WINDOW_OFFSET_DISABLE               0x80000000
+#define A4XX_RB_BIN_OFFSET_X__MASK                             0x00007fff
+#define A4XX_RB_BIN_OFFSET_X__SHIFT                            0
+static inline uint32_t A4XX_RB_BIN_OFFSET_X(uint32_t val)
+{
+       return ((val) << A4XX_RB_BIN_OFFSET_X__SHIFT) & A4XX_RB_BIN_OFFSET_X__MASK;
+}
+#define A4XX_RB_BIN_OFFSET_Y__MASK                             0x7fff0000
+#define A4XX_RB_BIN_OFFSET_Y__SHIFT                            16
+static inline uint32_t A4XX_RB_BIN_OFFSET_Y(uint32_t val)
+{
+       return ((val) << A4XX_RB_BIN_OFFSET_Y__SHIFT) & A4XX_RB_BIN_OFFSET_Y__MASK;
+}
+
+#define REG_A4XX_RB_VPORT_Z_CLAMP_MAX_15                       0x0000213f
+
+#define REG_A4XX_RBBM_HW_VERSION                               0x00000000
+
+#define REG_A4XX_RBBM_HW_CONFIGURATION                         0x00000002
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_CTL_TP(uint32_t i0) { return 0x00000004 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_CTL_TP_REG(uint32_t i0) { return 0x00000004 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_CTL2_TP(uint32_t i0) { return 0x00000008 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_CTL2_TP_REG(uint32_t i0) { return 0x00000008 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_HYST_TP(uint32_t i0) { return 0x0000000c + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_HYST_TP_REG(uint32_t i0) { return 0x0000000c + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_DELAY_TP(uint32_t i0) { return 0x00000010 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_DELAY_TP_REG(uint32_t i0) { return 0x00000010 + 0x1*i0; }
+
+#define REG_A4XX_RBBM_CLOCK_CTL_UCHE                           0x00000014
+
+#define REG_A4XX_RBBM_CLOCK_CTL2_UCHE                          0x00000015
+
+#define REG_A4XX_RBBM_CLOCK_CTL3_UCHE                          0x00000016
+
+#define REG_A4XX_RBBM_CLOCK_CTL4_UCHE                          0x00000017
+
+#define REG_A4XX_RBBM_CLOCK_HYST_UCHE                          0x00000018
+
+#define REG_A4XX_RBBM_CLOCK_DELAY_UCHE                         0x00000019
+
+#define REG_A4XX_RBBM_CLOCK_MODE_GPC                           0x0000001a
+
+#define REG_A4XX_RBBM_CLOCK_DELAY_GPC                          0x0000001b
+
+#define REG_A4XX_RBBM_CLOCK_HYST_GPC                           0x0000001c
+
+#define REG_A4XX_RBBM_CLOCK_CTL_TSE_RAS_RBBM                   0x0000001d
+
+#define REG_A4XX_RBBM_CLOCK_HYST_TSE_RAS_RBBM                  0x0000001e
+
+#define REG_A4XX_RBBM_CLOCK_DELAY_TSE_RAS_RBBM                 0x0000001f
+
+#define REG_A4XX_RBBM_CLOCK_CTL                                        0x00000020
+
+#define REG_A4XX_RBBM_SP_HYST_CNT                              0x00000021
+
+#define REG_A4XX_RBBM_SW_RESET_CMD                             0x00000022
+
+#define REG_A4XX_RBBM_AHB_CTL0                                 0x00000023
+
+#define REG_A4XX_RBBM_AHB_CTL1                                 0x00000024
+
+#define REG_A4XX_RBBM_AHB_CMD                                  0x00000025
+
+#define REG_A4XX_RBBM_RB_SUB_BLOCK_SEL_CTL                     0x00000026
+
+#define REG_A4XX_RBBM_RAM_ACC_63_32                            0x00000028
+
+#define REG_A4XX_RBBM_WAIT_IDLE_CLOCKS_CTL                     0x0000002b
+
+#define REG_A4XX_RBBM_INTERFACE_HANG_INT_CTL                   0x0000002f
+
+#define REG_A4XX_RBBM_INTERFACE_HANG_MASK_CTL4                 0x00000034
+
+#define REG_A4XX_RBBM_INT_CLEAR_CMD                            0x00000036
+
+#define REG_A4XX_RBBM_INT_0_MASK                               0x00000037
+
+#define REG_A4XX_RBBM_RBBM_CTL                                 0x0000003e
+
+#define REG_A4XX_RBBM_AHB_DEBUG_CTL                            0x0000003f
+
+#define REG_A4XX_RBBM_VBIF_DEBUG_CTL                           0x00000041
+
+#define REG_A4XX_RBBM_CLOCK_CTL2                               0x00000042
+
+#define REG_A4XX_RBBM_BLOCK_SW_RESET_CMD                       0x00000045
+
+#define REG_A4XX_RBBM_RESET_CYCLES                             0x00000047
+
+#define REG_A4XX_RBBM_EXT_TRACE_BUS_CTL                                0x00000049
+
+#define REG_A4XX_RBBM_CFG_DEBBUS_SEL_A                         0x0000004a
+
+#define REG_A4XX_RBBM_CFG_DEBBUS_SEL_B                         0x0000004b
+
+#define REG_A4XX_RBBM_CFG_DEBBUS_SEL_C                         0x0000004c
+
+#define REG_A4XX_RBBM_CFG_DEBBUS_SEL_D                         0x0000004d
+
+#define REG_A4XX_RBBM_PERFCTR_CP_0_LO                          0x0000009c
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_CTL_SP(uint32_t i0) { return 0x00000068 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_CTL_SP_REG(uint32_t i0) { return 0x00000068 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_CTL2_SP(uint32_t i0) { return 0x0000006c + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_CTL2_SP_REG(uint32_t i0) { return 0x0000006c + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_HYST_SP(uint32_t i0) { return 0x00000070 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_HYST_SP_REG(uint32_t i0) { return 0x00000070 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_DELAY_SP(uint32_t i0) { return 0x00000074 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_DELAY_SP_REG(uint32_t i0) { return 0x00000074 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_CTL_RB(uint32_t i0) { return 0x00000078 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_CTL_RB_REG(uint32_t i0) { return 0x00000078 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_CTL2_RB(uint32_t i0) { return 0x0000007c + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_CTL2_RB_REG(uint32_t i0) { return 0x0000007c + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_CTL_MARB_CCU(uint32_t i0) { return 0x00000082 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_CTL_MARB_CCU_REG(uint32_t i0) { return 0x00000082 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_HYST_RB_MARB_CCU(uint32_t i0) { return 0x00000086 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_HYST_RB_MARB_CCU_REG(uint32_t i0) { return 0x00000086 + 0x1*i0; }
+
+#define REG_A4XX_RBBM_CLOCK_HYST_COM_DCOM                      0x00000080
+
+#define REG_A4XX_RBBM_CLOCK_CTL_COM_DCOM                       0x00000081
+
+#define REG_A4XX_RBBM_CLOCK_CTL_HLSQ                           0x0000008a
+
+#define REG_A4XX_RBBM_CLOCK_HYST_HLSQ                          0x0000008b
+
+#define REG_A4XX_RBBM_CLOCK_DELAY_HLSQ                         0x0000008c
+
+#define REG_A4XX_RBBM_CLOCK_DELAY_COM_DCOM                     0x0000008d
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_DELAY_RB_MARB_CCU_L1(uint32_t i0) { return 0x0000008e + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_RBBM_CLOCK_DELAY_RB_MARB_CCU_L1_REG(uint32_t i0) { return 0x0000008e + 0x1*i0; }
+
+#define REG_A4XX_RBBM_PERFCTR_PWR_1_LO                         0x00000168
+
+#define REG_A4XX_RBBM_PERFCTR_CTL                              0x00000170
+
+#define REG_A4XX_RBBM_PERFCTR_LOAD_CMD0                                0x00000171
+
+#define REG_A4XX_RBBM_PERFCTR_LOAD_CMD1                                0x00000172
+
+#define REG_A4XX_RBBM_PERFCTR_LOAD_CMD2                                0x00000173
+
+#define REG_A4XX_RBBM_PERFCTR_LOAD_VALUE_LO                    0x00000174
+
+#define REG_A4XX_RBBM_PERFCTR_LOAD_VALUE_HI                    0x00000175
+
+#define REG_A4XX_RBBM_GPU_BUSY_MASKED                          0x0000017a
+
+#define REG_A4XX_RBBM_INT_0_STATUS                             0x0000017d
+
+#define REG_A4XX_RBBM_CLOCK_STATUS                             0x00000182
+
+#define REG_A4XX_RBBM_AHB_STATUS                               0x00000189
+
+#define REG_A4XX_RBBM_AHB_ME_SPLIT_STATUS                      0x0000018c
+
+#define REG_A4XX_RBBM_AHB_PFP_SPLIT_STATUS                     0x0000018d
+
+#define REG_A4XX_RBBM_AHB_ERROR_STATUS                         0x0000018f
+
+#define REG_A4XX_RBBM_STATUS                                   0x00000191
+#define A4XX_RBBM_STATUS_HI_BUSY                               0x00000001
+#define A4XX_RBBM_STATUS_CP_ME_BUSY                            0x00000002
+#define A4XX_RBBM_STATUS_CP_PFP_BUSY                           0x00000004
+#define A4XX_RBBM_STATUS_CP_NRT_BUSY                           0x00004000
+#define A4XX_RBBM_STATUS_VBIF_BUSY                             0x00008000
+#define A4XX_RBBM_STATUS_TSE_BUSY                              0x00010000
+#define A4XX_RBBM_STATUS_RAS_BUSY                              0x00020000
+#define A4XX_RBBM_STATUS_RB_BUSY                               0x00040000
+#define A4XX_RBBM_STATUS_PC_DCALL_BUSY                         0x00080000
+#define A4XX_RBBM_STATUS_PC_VSD_BUSY                           0x00100000
+#define A4XX_RBBM_STATUS_VFD_BUSY                              0x00200000
+#define A4XX_RBBM_STATUS_VPC_BUSY                              0x00400000
+#define A4XX_RBBM_STATUS_UCHE_BUSY                             0x00800000
+#define A4XX_RBBM_STATUS_SP_BUSY                               0x01000000
+#define A4XX_RBBM_STATUS_TPL1_BUSY                             0x02000000
+#define A4XX_RBBM_STATUS_MARB_BUSY                             0x04000000
+#define A4XX_RBBM_STATUS_VSC_BUSY                              0x08000000
+#define A4XX_RBBM_STATUS_ARB_BUSY                              0x10000000
+#define A4XX_RBBM_STATUS_HLSQ_BUSY                             0x20000000
+#define A4XX_RBBM_STATUS_GPU_BUSY_NOHC                         0x40000000
+#define A4XX_RBBM_STATUS_GPU_BUSY                              0x80000000
+
+#define REG_A4XX_RBBM_INTERFACE_RRDY_STATUS5                   0x0000019f
+
+#define REG_A4XX_CP_SCRATCH_UMASK                              0x00000228
+
+#define REG_A4XX_CP_SCRATCH_ADDR                               0x00000229
+
+#define REG_A4XX_CP_RB_BASE                                    0x00000200
+
+#define REG_A4XX_CP_RB_CNTL                                    0x00000201
+
+#define REG_A4XX_CP_RB_WPTR                                    0x00000205
+
+#define REG_A4XX_CP_RB_RPTR_ADDR                               0x00000203
+
+#define REG_A4XX_CP_RB_RPTR                                    0x00000204
+
+#define REG_A4XX_CP_IB1_BASE                                   0x00000206
+
+#define REG_A4XX_CP_IB1_BUFSZ                                  0x00000207
+
+#define REG_A4XX_CP_IB2_BASE                                   0x00000208
+
+#define REG_A4XX_CP_IB2_BUFSZ                                  0x00000209
+
+#define REG_A4XX_CP_ME_RB_DONE_DATA                            0x00000217
+
+#define REG_A4XX_CP_QUEUE_THRESH2                              0x00000219
+
+#define REG_A4XX_CP_MERCIU_SIZE                                        0x0000021b
+
+#define REG_A4XX_CP_ROQ_ADDR                                   0x0000021c
+
+#define REG_A4XX_CP_ROQ_DATA                                   0x0000021d
+
+#define REG_A4XX_CP_MEQ_ADDR                                   0x0000021e
+
+#define REG_A4XX_CP_MEQ_DATA                                   0x0000021f
+
+#define REG_A4XX_CP_MERCIU_ADDR                                        0x00000220
+
+#define REG_A4XX_CP_MERCIU_DATA                                        0x00000221
+
+#define REG_A4XX_CP_MERCIU_DATA2                               0x00000222
+
+#define REG_A4XX_CP_PFP_UCODE_ADDR                             0x00000223
+
+#define REG_A4XX_CP_PFP_UCODE_DATA                             0x00000224
+
+#define REG_A4XX_CP_ME_RAM_WADDR                               0x00000225
+
+#define REG_A4XX_CP_ME_RAM_RADDR                               0x00000226
+
+#define REG_A4XX_CP_ME_RAM_DATA                                        0x00000227
+
+#define REG_A4XX_CP_PREEMPT                                    0x0000022a
+
+#define REG_A4XX_CP_CNTL                                       0x0000022c
+
+#define REG_A4XX_CP_ME_CNTL                                    0x0000022d
+
+#define REG_A4XX_CP_DEBUG                                      0x0000022e
+
+#define REG_A4XX_CP_DEBUG_ECO_CONTROL                          0x00000231
+
+#define REG_A4XX_CP_DRAW_STATE_ADDR                            0x00000232
+
+#define REG_A4XX_CP_PROTECT_REG_0                              0x00000240
+
+static inline uint32_t REG_A4XX_CP_PROTECT(uint32_t i0) { return 0x00000240 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_CP_PROTECT_REG(uint32_t i0) { return 0x00000240 + 0x1*i0; }
+
+#define REG_A4XX_CP_PROTECT_CTRL                               0x00000250
+
+#define REG_A4XX_CP_ST_BASE                                    0x000004c0
+
+#define REG_A4XX_CP_STQ_AVAIL                                  0x000004ce
+
+#define REG_A4XX_CP_MERCIU_STAT                                        0x000004d0
+
+#define REG_A4XX_CP_WFI_PEND_CTR                               0x000004d2
+
+#define REG_A4XX_CP_HW_FAULT                                   0x000004d8
+
+#define REG_A4XX_CP_PROTECT_STATUS                             0x000004da
+
+#define REG_A4XX_CP_EVENTS_IN_FLIGHT                           0x000004dd
+
+#define REG_A4XX_CP_PERFCTR_CP_SEL_0                           0x00000500
+
+#define REG_A4XX_CP_PERFCOMBINER_SELECT                                0x0000050b
+
+static inline uint32_t REG_A4XX_CP_SCRATCH(uint32_t i0) { return 0x00000578 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_CP_SCRATCH_REG(uint32_t i0) { return 0x00000578 + 0x1*i0; }
+
+#define REG_A4XX_SP_VS_STATUS                                  0x00000ec0
+
+#define REG_A4XX_SP_PERFCTR_SP_SEL_11                          0x00000ecf
+
+#define REG_A4XX_SP_SP_CTRL_REG                                        0x000022c0
+#define A4XX_SP_SP_CTRL_REG_BINNING_PASS                       0x00080000
+
+#define REG_A4XX_SP_INSTR_CACHE_CTRL                           0x000022c1
+
+#define REG_A4XX_SP_VS_CTRL_REG0                               0x000022c4
+#define A4XX_SP_VS_CTRL_REG0_THREADMODE__MASK                  0x00000001
+#define A4XX_SP_VS_CTRL_REG0_THREADMODE__SHIFT                 0
+static inline uint32_t A4XX_SP_VS_CTRL_REG0_THREADMODE(enum a3xx_threadmode val)
+{
+       return ((val) << A4XX_SP_VS_CTRL_REG0_THREADMODE__SHIFT) & A4XX_SP_VS_CTRL_REG0_THREADMODE__MASK;
+}
+#define A4XX_SP_VS_CTRL_REG0_VARYING                           0x00000002
+#define A4XX_SP_VS_CTRL_REG0_CACHEINVALID                      0x00000004
+#define A4XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__MASK            0x000003f0
+#define A4XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT           4
+static inline uint32_t A4XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT) & A4XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__MASK;
+}
+#define A4XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__MASK            0x0003fc00
+#define A4XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT           10
+static inline uint32_t A4XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT) & A4XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__MASK;
+}
+#define A4XX_SP_VS_CTRL_REG0_INOUTREGOVERLAP__MASK             0x000c0000
+#define A4XX_SP_VS_CTRL_REG0_INOUTREGOVERLAP__SHIFT            18
+static inline uint32_t A4XX_SP_VS_CTRL_REG0_INOUTREGOVERLAP(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_CTRL_REG0_INOUTREGOVERLAP__SHIFT) & A4XX_SP_VS_CTRL_REG0_INOUTREGOVERLAP__MASK;
+}
+#define A4XX_SP_VS_CTRL_REG0_THREADSIZE__MASK                  0x00100000
+#define A4XX_SP_VS_CTRL_REG0_THREADSIZE__SHIFT                 20
+static inline uint32_t A4XX_SP_VS_CTRL_REG0_THREADSIZE(enum a3xx_threadsize val)
+{
+       return ((val) << A4XX_SP_VS_CTRL_REG0_THREADSIZE__SHIFT) & A4XX_SP_VS_CTRL_REG0_THREADSIZE__MASK;
+}
+#define A4XX_SP_VS_CTRL_REG0_SUPERTHREADMODE                   0x00200000
+#define A4XX_SP_VS_CTRL_REG0_PIXLODENABLE                      0x00400000
+
+#define REG_A4XX_SP_VS_CTRL_REG1                               0x000022c5
+#define A4XX_SP_VS_CTRL_REG1_CONSTLENGTH__MASK                 0x000000ff
+#define A4XX_SP_VS_CTRL_REG1_CONSTLENGTH__SHIFT                        0
+static inline uint32_t A4XX_SP_VS_CTRL_REG1_CONSTLENGTH(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_CTRL_REG1_CONSTLENGTH__SHIFT) & A4XX_SP_VS_CTRL_REG1_CONSTLENGTH__MASK;
+}
+#define A4XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING__MASK          0x7f000000
+#define A4XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING__SHIFT         24
+static inline uint32_t A4XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING__SHIFT) & A4XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING__MASK;
+}
+
+#define REG_A4XX_SP_VS_PARAM_REG                               0x000022c6
+#define A4XX_SP_VS_PARAM_REG_POSREGID__MASK                    0x000000ff
+#define A4XX_SP_VS_PARAM_REG_POSREGID__SHIFT                   0
+static inline uint32_t A4XX_SP_VS_PARAM_REG_POSREGID(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_PARAM_REG_POSREGID__SHIFT) & A4XX_SP_VS_PARAM_REG_POSREGID__MASK;
+}
+#define A4XX_SP_VS_PARAM_REG_PSIZEREGID__MASK                  0x0000ff00
+#define A4XX_SP_VS_PARAM_REG_PSIZEREGID__SHIFT                 8
+static inline uint32_t A4XX_SP_VS_PARAM_REG_PSIZEREGID(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_PARAM_REG_PSIZEREGID__SHIFT) & A4XX_SP_VS_PARAM_REG_PSIZEREGID__MASK;
+}
+#define A4XX_SP_VS_PARAM_REG_TOTALVSOUTVAR__MASK               0xfff00000
+#define A4XX_SP_VS_PARAM_REG_TOTALVSOUTVAR__SHIFT              20
+static inline uint32_t A4XX_SP_VS_PARAM_REG_TOTALVSOUTVAR(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_PARAM_REG_TOTALVSOUTVAR__SHIFT) & A4XX_SP_VS_PARAM_REG_TOTALVSOUTVAR__MASK;
+}
+
+static inline uint32_t REG_A4XX_SP_VS_OUT(uint32_t i0) { return 0x000022c7 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_SP_VS_OUT_REG(uint32_t i0) { return 0x000022c7 + 0x1*i0; }
+#define A4XX_SP_VS_OUT_REG_A_REGID__MASK                       0x000001ff
+#define A4XX_SP_VS_OUT_REG_A_REGID__SHIFT                      0
+static inline uint32_t A4XX_SP_VS_OUT_REG_A_REGID(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_OUT_REG_A_REGID__SHIFT) & A4XX_SP_VS_OUT_REG_A_REGID__MASK;
+}
+#define A4XX_SP_VS_OUT_REG_A_COMPMASK__MASK                    0x00001e00
+#define A4XX_SP_VS_OUT_REG_A_COMPMASK__SHIFT                   9
+static inline uint32_t A4XX_SP_VS_OUT_REG_A_COMPMASK(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_OUT_REG_A_COMPMASK__SHIFT) & A4XX_SP_VS_OUT_REG_A_COMPMASK__MASK;
+}
+#define A4XX_SP_VS_OUT_REG_B_REGID__MASK                       0x01ff0000
+#define A4XX_SP_VS_OUT_REG_B_REGID__SHIFT                      16
+static inline uint32_t A4XX_SP_VS_OUT_REG_B_REGID(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_OUT_REG_B_REGID__SHIFT) & A4XX_SP_VS_OUT_REG_B_REGID__MASK;
+}
+#define A4XX_SP_VS_OUT_REG_B_COMPMASK__MASK                    0x1e000000
+#define A4XX_SP_VS_OUT_REG_B_COMPMASK__SHIFT                   25
+static inline uint32_t A4XX_SP_VS_OUT_REG_B_COMPMASK(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_OUT_REG_B_COMPMASK__SHIFT) & A4XX_SP_VS_OUT_REG_B_COMPMASK__MASK;
+}
+
+static inline uint32_t REG_A4XX_SP_VS_VPC_DST(uint32_t i0) { return 0x000022d8 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_SP_VS_VPC_DST_REG(uint32_t i0) { return 0x000022d8 + 0x1*i0; }
+#define A4XX_SP_VS_VPC_DST_REG_OUTLOC0__MASK                   0x000000ff
+#define A4XX_SP_VS_VPC_DST_REG_OUTLOC0__SHIFT                  0
+static inline uint32_t A4XX_SP_VS_VPC_DST_REG_OUTLOC0(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_VPC_DST_REG_OUTLOC0__SHIFT) & A4XX_SP_VS_VPC_DST_REG_OUTLOC0__MASK;
+}
+#define A4XX_SP_VS_VPC_DST_REG_OUTLOC1__MASK                   0x0000ff00
+#define A4XX_SP_VS_VPC_DST_REG_OUTLOC1__SHIFT                  8
+static inline uint32_t A4XX_SP_VS_VPC_DST_REG_OUTLOC1(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_VPC_DST_REG_OUTLOC1__SHIFT) & A4XX_SP_VS_VPC_DST_REG_OUTLOC1__MASK;
+}
+#define A4XX_SP_VS_VPC_DST_REG_OUTLOC2__MASK                   0x00ff0000
+#define A4XX_SP_VS_VPC_DST_REG_OUTLOC2__SHIFT                  16
+static inline uint32_t A4XX_SP_VS_VPC_DST_REG_OUTLOC2(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_VPC_DST_REG_OUTLOC2__SHIFT) & A4XX_SP_VS_VPC_DST_REG_OUTLOC2__MASK;
+}
+#define A4XX_SP_VS_VPC_DST_REG_OUTLOC3__MASK                   0xff000000
+#define A4XX_SP_VS_VPC_DST_REG_OUTLOC3__SHIFT                  24
+static inline uint32_t A4XX_SP_VS_VPC_DST_REG_OUTLOC3(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_VPC_DST_REG_OUTLOC3__SHIFT) & A4XX_SP_VS_VPC_DST_REG_OUTLOC3__MASK;
+}
+
+#define REG_A4XX_SP_VS_OBJ_OFFSET_REG                          0x000022e0
+#define A4XX_SP_VS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK      0x01ff0000
+#define A4XX_SP_VS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT     16
+static inline uint32_t A4XX_SP_VS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT) & A4XX_SP_VS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK;
+}
+#define A4XX_SP_VS_OBJ_OFFSET_REG_SHADEROBJOFFSET__MASK                0xfe000000
+#define A4XX_SP_VS_OBJ_OFFSET_REG_SHADEROBJOFFSET__SHIFT       25
+static inline uint32_t A4XX_SP_VS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_SP_VS_OBJ_OFFSET_REG_SHADEROBJOFFSET__SHIFT) & A4XX_SP_VS_OBJ_OFFSET_REG_SHADEROBJOFFSET__MASK;
+}
+
+#define REG_A4XX_SP_VS_OBJ_START                               0x000022e1
+
+#define REG_A4XX_SP_VS_PVT_MEM_PARAM                           0x000022e2
+
+#define REG_A4XX_SP_VS_PVT_MEM_ADDR                            0x000022e3
+
+#define REG_A4XX_SP_VS_LENGTH_REG                              0x000022e5
+
+#define REG_A4XX_SP_FS_CTRL_REG0                               0x000022e8
+#define A4XX_SP_FS_CTRL_REG0_THREADMODE__MASK                  0x00000001
+#define A4XX_SP_FS_CTRL_REG0_THREADMODE__SHIFT                 0
+static inline uint32_t A4XX_SP_FS_CTRL_REG0_THREADMODE(enum a3xx_threadmode val)
+{
+       return ((val) << A4XX_SP_FS_CTRL_REG0_THREADMODE__SHIFT) & A4XX_SP_FS_CTRL_REG0_THREADMODE__MASK;
+}
+#define A4XX_SP_FS_CTRL_REG0_VARYING                           0x00000002
+#define A4XX_SP_FS_CTRL_REG0_CACHEINVALID                      0x00000004
+#define A4XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__MASK            0x000003f0
+#define A4XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT           4
+static inline uint32_t A4XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT(uint32_t val)
+{
+       return ((val) << A4XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT) & A4XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__MASK;
+}
+#define A4XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__MASK            0x0003fc00
+#define A4XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT           10
+static inline uint32_t A4XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT(uint32_t val)
+{
+       return ((val) << A4XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT) & A4XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__MASK;
+}
+#define A4XX_SP_FS_CTRL_REG0_INOUTREGOVERLAP__MASK             0x000c0000
+#define A4XX_SP_FS_CTRL_REG0_INOUTREGOVERLAP__SHIFT            18
+static inline uint32_t A4XX_SP_FS_CTRL_REG0_INOUTREGOVERLAP(uint32_t val)
+{
+       return ((val) << A4XX_SP_FS_CTRL_REG0_INOUTREGOVERLAP__SHIFT) & A4XX_SP_FS_CTRL_REG0_INOUTREGOVERLAP__MASK;
+}
+#define A4XX_SP_FS_CTRL_REG0_THREADSIZE__MASK                  0x00100000
+#define A4XX_SP_FS_CTRL_REG0_THREADSIZE__SHIFT                 20
+static inline uint32_t A4XX_SP_FS_CTRL_REG0_THREADSIZE(enum a3xx_threadsize val)
+{
+       return ((val) << A4XX_SP_FS_CTRL_REG0_THREADSIZE__SHIFT) & A4XX_SP_FS_CTRL_REG0_THREADSIZE__MASK;
+}
+#define A4XX_SP_FS_CTRL_REG0_SUPERTHREADMODE                   0x00200000
+#define A4XX_SP_FS_CTRL_REG0_PIXLODENABLE                      0x00400000
+
+#define REG_A4XX_SP_FS_CTRL_REG1                               0x000022e9
+#define A4XX_SP_FS_CTRL_REG1_CONSTLENGTH__MASK                 0x000000ff
+#define A4XX_SP_FS_CTRL_REG1_CONSTLENGTH__SHIFT                        0
+static inline uint32_t A4XX_SP_FS_CTRL_REG1_CONSTLENGTH(uint32_t val)
+{
+       return ((val) << A4XX_SP_FS_CTRL_REG1_CONSTLENGTH__SHIFT) & A4XX_SP_FS_CTRL_REG1_CONSTLENGTH__MASK;
+}
+#define A4XX_SP_FS_CTRL_REG1_VARYING                           0x00100000
+
+#define REG_A4XX_SP_FS_OBJ_OFFSET_REG                          0x000022ea
+#define A4XX_SP_FS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK      0x01ff0000
+#define A4XX_SP_FS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT     16
+static inline uint32_t A4XX_SP_FS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_SP_FS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT) & A4XX_SP_FS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK;
+}
+#define A4XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET__MASK                0xfe000000
+#define A4XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET__SHIFT       25
+static inline uint32_t A4XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET__SHIFT) & A4XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET__MASK;
+}
+
+#define REG_A4XX_SP_FS_OBJ_START                               0x000022eb
+
+#define REG_A4XX_SP_FS_PVT_MEM_PARAM                           0x000022ec
+
+#define REG_A4XX_SP_FS_PVT_MEM_ADDR                            0x000022ed
+
+#define REG_A4XX_SP_FS_LENGTH_REG                              0x000022ef
+
+#define REG_A4XX_SP_FS_OUTPUT_REG                              0x000022f0
+#define A4XX_SP_FS_OUTPUT_REG_DEPTH_ENABLE                     0x00000080
+#define A4XX_SP_FS_OUTPUT_REG_DEPTH_REGID__MASK                        0x0000ff00
+#define A4XX_SP_FS_OUTPUT_REG_DEPTH_REGID__SHIFT               8
+static inline uint32_t A4XX_SP_FS_OUTPUT_REG_DEPTH_REGID(uint32_t val)
+{
+       return ((val) << A4XX_SP_FS_OUTPUT_REG_DEPTH_REGID__SHIFT) & A4XX_SP_FS_OUTPUT_REG_DEPTH_REGID__MASK;
+}
+
+static inline uint32_t REG_A4XX_SP_FS_MRT(uint32_t i0) { return 0x000022f1 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_SP_FS_MRT_REG(uint32_t i0) { return 0x000022f1 + 0x1*i0; }
+#define A4XX_SP_FS_MRT_REG_REGID__MASK                         0x000000ff
+#define A4XX_SP_FS_MRT_REG_REGID__SHIFT                                0
+static inline uint32_t A4XX_SP_FS_MRT_REG_REGID(uint32_t val)
+{
+       return ((val) << A4XX_SP_FS_MRT_REG_REGID__SHIFT) & A4XX_SP_FS_MRT_REG_REGID__MASK;
+}
+#define A4XX_SP_FS_MRT_REG_HALF_PRECISION                      0x00000100
+#define A4XX_SP_FS_MRT_REG_MRTFORMAT__MASK                     0x0003f000
+#define A4XX_SP_FS_MRT_REG_MRTFORMAT__SHIFT                    12
+static inline uint32_t A4XX_SP_FS_MRT_REG_MRTFORMAT(enum a4xx_color_fmt val)
+{
+       return ((val) << A4XX_SP_FS_MRT_REG_MRTFORMAT__SHIFT) & A4XX_SP_FS_MRT_REG_MRTFORMAT__MASK;
+}
+
+#define REG_A4XX_SP_HS_OBJ_OFFSET_REG                          0x0000230d
+#define A4XX_SP_HS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK      0x01ff0000
+#define A4XX_SP_HS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT     16
+static inline uint32_t A4XX_SP_HS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_SP_HS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT) & A4XX_SP_HS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK;
+}
+#define A4XX_SP_HS_OBJ_OFFSET_REG_SHADEROBJOFFSET__MASK                0xfe000000
+#define A4XX_SP_HS_OBJ_OFFSET_REG_SHADEROBJOFFSET__SHIFT       25
+static inline uint32_t A4XX_SP_HS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_SP_HS_OBJ_OFFSET_REG_SHADEROBJOFFSET__SHIFT) & A4XX_SP_HS_OBJ_OFFSET_REG_SHADEROBJOFFSET__MASK;
+}
+
+#define REG_A4XX_SP_DS_OBJ_OFFSET_REG                          0x00002334
+#define A4XX_SP_DS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK      0x01ff0000
+#define A4XX_SP_DS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT     16
+static inline uint32_t A4XX_SP_DS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_SP_DS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT) & A4XX_SP_DS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK;
+}
+#define A4XX_SP_DS_OBJ_OFFSET_REG_SHADEROBJOFFSET__MASK                0xfe000000
+#define A4XX_SP_DS_OBJ_OFFSET_REG_SHADEROBJOFFSET__SHIFT       25
+static inline uint32_t A4XX_SP_DS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_SP_DS_OBJ_OFFSET_REG_SHADEROBJOFFSET__SHIFT) & A4XX_SP_DS_OBJ_OFFSET_REG_SHADEROBJOFFSET__MASK;
+}
+
+#define REG_A4XX_SP_GS_OBJ_OFFSET_REG                          0x0000235b
+#define A4XX_SP_GS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK      0x01ff0000
+#define A4XX_SP_GS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT     16
+static inline uint32_t A4XX_SP_GS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_SP_GS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT) & A4XX_SP_GS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK;
+}
+#define A4XX_SP_GS_OBJ_OFFSET_REG_SHADEROBJOFFSET__MASK                0xfe000000
+#define A4XX_SP_GS_OBJ_OFFSET_REG_SHADEROBJOFFSET__SHIFT       25
+static inline uint32_t A4XX_SP_GS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_SP_GS_OBJ_OFFSET_REG_SHADEROBJOFFSET__SHIFT) & A4XX_SP_GS_OBJ_OFFSET_REG_SHADEROBJOFFSET__MASK;
+}
+
+#define REG_A4XX_SP_GS_LENGTH_REG                              0x00002360
+
+#define REG_A4XX_VPC_DEBUG_RAM_SEL                             0x00000e60
+
+#define REG_A4XX_VPC_DEBUG_RAM_READ                            0x00000e61
+
+#define REG_A4XX_VPC_DEBUG_ECO_CONTROL                         0x00000e64
+
+#define REG_A4XX_VPC_PERFCTR_VPC_SEL_3                         0x00000e68
+
+#define REG_A4XX_VPC_ATTR                                      0x00002140
+#define A4XX_VPC_ATTR_TOTALATTR__MASK                          0x000001ff
+#define A4XX_VPC_ATTR_TOTALATTR__SHIFT                         0
+static inline uint32_t A4XX_VPC_ATTR_TOTALATTR(uint32_t val)
+{
+       return ((val) << A4XX_VPC_ATTR_TOTALATTR__SHIFT) & A4XX_VPC_ATTR_TOTALATTR__MASK;
+}
+#define A4XX_VPC_ATTR_PSIZE                                    0x00000200
+#define A4XX_VPC_ATTR_THRDASSIGN__MASK                         0x00003000
+#define A4XX_VPC_ATTR_THRDASSIGN__SHIFT                                12
+static inline uint32_t A4XX_VPC_ATTR_THRDASSIGN(uint32_t val)
+{
+       return ((val) << A4XX_VPC_ATTR_THRDASSIGN__SHIFT) & A4XX_VPC_ATTR_THRDASSIGN__MASK;
+}
+#define A4XX_VPC_ATTR_ENABLE                                   0x02000000
+
+#define REG_A4XX_VPC_PACK                                      0x00002141
+#define A4XX_VPC_PACK_NUMBYPASSVAR__MASK                       0x000000ff
+#define A4XX_VPC_PACK_NUMBYPASSVAR__SHIFT                      0
+static inline uint32_t A4XX_VPC_PACK_NUMBYPASSVAR(uint32_t val)
+{
+       return ((val) << A4XX_VPC_PACK_NUMBYPASSVAR__SHIFT) & A4XX_VPC_PACK_NUMBYPASSVAR__MASK;
+}
+#define A4XX_VPC_PACK_NUMFPNONPOSVAR__MASK                     0x0000ff00
+#define A4XX_VPC_PACK_NUMFPNONPOSVAR__SHIFT                    8
+static inline uint32_t A4XX_VPC_PACK_NUMFPNONPOSVAR(uint32_t val)
+{
+       return ((val) << A4XX_VPC_PACK_NUMFPNONPOSVAR__SHIFT) & A4XX_VPC_PACK_NUMFPNONPOSVAR__MASK;
+}
+#define A4XX_VPC_PACK_NUMNONPOSVSVAR__MASK                     0x00ff0000
+#define A4XX_VPC_PACK_NUMNONPOSVSVAR__SHIFT                    16
+static inline uint32_t A4XX_VPC_PACK_NUMNONPOSVSVAR(uint32_t val)
+{
+       return ((val) << A4XX_VPC_PACK_NUMNONPOSVSVAR__SHIFT) & A4XX_VPC_PACK_NUMNONPOSVSVAR__MASK;
+}
+
+static inline uint32_t REG_A4XX_VPC_VARYING_INTERP(uint32_t i0) { return 0x00002142 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_VPC_VARYING_INTERP_MODE(uint32_t i0) { return 0x00002142 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_VPC_VARYING_PS_REPL(uint32_t i0) { return 0x0000214a + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_VPC_VARYING_PS_REPL_MODE(uint32_t i0) { return 0x0000214a + 0x1*i0; }
+
+#define REG_A4XX_VPC_SO_FLUSH_WADDR_3                          0x0000216e
+
+#define REG_A4XX_VSC_BIN_SIZE                                  0x00000c00
+#define A4XX_VSC_BIN_SIZE_WIDTH__MASK                          0x0000001f
+#define A4XX_VSC_BIN_SIZE_WIDTH__SHIFT                         0
+static inline uint32_t A4XX_VSC_BIN_SIZE_WIDTH(uint32_t val)
+{
+       return ((val >> 5) << A4XX_VSC_BIN_SIZE_WIDTH__SHIFT) & A4XX_VSC_BIN_SIZE_WIDTH__MASK;
+}
+#define A4XX_VSC_BIN_SIZE_HEIGHT__MASK                         0x000003e0
+#define A4XX_VSC_BIN_SIZE_HEIGHT__SHIFT                                5
+static inline uint32_t A4XX_VSC_BIN_SIZE_HEIGHT(uint32_t val)
+{
+       return ((val >> 5) << A4XX_VSC_BIN_SIZE_HEIGHT__SHIFT) & A4XX_VSC_BIN_SIZE_HEIGHT__MASK;
+}
+
+#define REG_A4XX_VSC_SIZE_ADDRESS                              0x00000c01
+
+#define REG_A4XX_VSC_SIZE_ADDRESS2                             0x00000c02
+
+#define REG_A4XX_VSC_DEBUG_ECO_CONTROL                         0x00000c03
+
+static inline uint32_t REG_A4XX_VSC_PIPE_CONFIG(uint32_t i0) { return 0x00000c08 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_VSC_PIPE_CONFIG_REG(uint32_t i0) { return 0x00000c08 + 0x1*i0; }
+#define A4XX_VSC_PIPE_CONFIG_REG_X__MASK                       0x000003ff
+#define A4XX_VSC_PIPE_CONFIG_REG_X__SHIFT                      0
+static inline uint32_t A4XX_VSC_PIPE_CONFIG_REG_X(uint32_t val)
+{
+       return ((val) << A4XX_VSC_PIPE_CONFIG_REG_X__SHIFT) & A4XX_VSC_PIPE_CONFIG_REG_X__MASK;
+}
+#define A4XX_VSC_PIPE_CONFIG_REG_Y__MASK                       0x000ffc00
+#define A4XX_VSC_PIPE_CONFIG_REG_Y__SHIFT                      10
+static inline uint32_t A4XX_VSC_PIPE_CONFIG_REG_Y(uint32_t val)
+{
+       return ((val) << A4XX_VSC_PIPE_CONFIG_REG_Y__SHIFT) & A4XX_VSC_PIPE_CONFIG_REG_Y__MASK;
+}
+#define A4XX_VSC_PIPE_CONFIG_REG_W__MASK                       0x00f00000
+#define A4XX_VSC_PIPE_CONFIG_REG_W__SHIFT                      20
+static inline uint32_t A4XX_VSC_PIPE_CONFIG_REG_W(uint32_t val)
+{
+       return ((val) << A4XX_VSC_PIPE_CONFIG_REG_W__SHIFT) & A4XX_VSC_PIPE_CONFIG_REG_W__MASK;
+}
+#define A4XX_VSC_PIPE_CONFIG_REG_H__MASK                       0x0f000000
+#define A4XX_VSC_PIPE_CONFIG_REG_H__SHIFT                      24
+static inline uint32_t A4XX_VSC_PIPE_CONFIG_REG_H(uint32_t val)
+{
+       return ((val) << A4XX_VSC_PIPE_CONFIG_REG_H__SHIFT) & A4XX_VSC_PIPE_CONFIG_REG_H__MASK;
+}
+
+static inline uint32_t REG_A4XX_VSC_PIPE_DATA_ADDRESS(uint32_t i0) { return 0x00000c10 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_VSC_PIPE_DATA_ADDRESS_REG(uint32_t i0) { return 0x00000c10 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_VSC_PIPE_DATA_LENGTH(uint32_t i0) { return 0x00000c18 + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_VSC_PIPE_DATA_LENGTH_REG(uint32_t i0) { return 0x00000c18 + 0x1*i0; }
+
+#define REG_A4XX_VSC_PIPE_PARTIAL_POSN_1                       0x00000c41
+
+#define REG_A4XX_VSC_PERFCTR_VSC_SEL_0                         0x00000c50
+
+#define REG_A4XX_VSC_PERFCTR_VSC_SEL_1                         0x00000c51
+
+#define REG_A4XX_VFD_DEBUG_CONTROL                             0x00000e40
+
+#define REG_A4XX_VFD_PERFCTR_VFD_SEL_7                         0x00000e4a
+
+#define REG_A4XX_VFD_CONTROL_0                                 0x00002200
+#define A4XX_VFD_CONTROL_0_TOTALATTRTOVS__MASK                 0x000000ff
+#define A4XX_VFD_CONTROL_0_TOTALATTRTOVS__SHIFT                        0
+static inline uint32_t A4XX_VFD_CONTROL_0_TOTALATTRTOVS(uint32_t val)
+{
+       return ((val) << A4XX_VFD_CONTROL_0_TOTALATTRTOVS__SHIFT) & A4XX_VFD_CONTROL_0_TOTALATTRTOVS__MASK;
+}
+#define A4XX_VFD_CONTROL_0_BYPASSATTROVS__MASK                 0x0001fe00
+#define A4XX_VFD_CONTROL_0_BYPASSATTROVS__SHIFT                        9
+static inline uint32_t A4XX_VFD_CONTROL_0_BYPASSATTROVS(uint32_t val)
+{
+       return ((val) << A4XX_VFD_CONTROL_0_BYPASSATTROVS__SHIFT) & A4XX_VFD_CONTROL_0_BYPASSATTROVS__MASK;
+}
+#define A4XX_VFD_CONTROL_0_STRMDECINSTRCNT__MASK               0x03f00000
+#define A4XX_VFD_CONTROL_0_STRMDECINSTRCNT__SHIFT              20
+static inline uint32_t A4XX_VFD_CONTROL_0_STRMDECINSTRCNT(uint32_t val)
+{
+       return ((val) << A4XX_VFD_CONTROL_0_STRMDECINSTRCNT__SHIFT) & A4XX_VFD_CONTROL_0_STRMDECINSTRCNT__MASK;
+}
+#define A4XX_VFD_CONTROL_0_STRMFETCHINSTRCNT__MASK             0xfc000000
+#define A4XX_VFD_CONTROL_0_STRMFETCHINSTRCNT__SHIFT            26
+static inline uint32_t A4XX_VFD_CONTROL_0_STRMFETCHINSTRCNT(uint32_t val)
+{
+       return ((val) << A4XX_VFD_CONTROL_0_STRMFETCHINSTRCNT__SHIFT) & A4XX_VFD_CONTROL_0_STRMFETCHINSTRCNT__MASK;
+}
+
+#define REG_A4XX_VFD_CONTROL_1                                 0x00002201
+#define A4XX_VFD_CONTROL_1_MAXSTORAGE__MASK                    0x0000ffff
+#define A4XX_VFD_CONTROL_1_MAXSTORAGE__SHIFT                   0
+static inline uint32_t A4XX_VFD_CONTROL_1_MAXSTORAGE(uint32_t val)
+{
+       return ((val) << A4XX_VFD_CONTROL_1_MAXSTORAGE__SHIFT) & A4XX_VFD_CONTROL_1_MAXSTORAGE__MASK;
+}
+#define A4XX_VFD_CONTROL_1_REGID4VTX__MASK                     0x00ff0000
+#define A4XX_VFD_CONTROL_1_REGID4VTX__SHIFT                    16
+static inline uint32_t A4XX_VFD_CONTROL_1_REGID4VTX(uint32_t val)
+{
+       return ((val) << A4XX_VFD_CONTROL_1_REGID4VTX__SHIFT) & A4XX_VFD_CONTROL_1_REGID4VTX__MASK;
+}
+#define A4XX_VFD_CONTROL_1_REGID4INST__MASK                    0xff000000
+#define A4XX_VFD_CONTROL_1_REGID4INST__SHIFT                   24
+static inline uint32_t A4XX_VFD_CONTROL_1_REGID4INST(uint32_t val)
+{
+       return ((val) << A4XX_VFD_CONTROL_1_REGID4INST__SHIFT) & A4XX_VFD_CONTROL_1_REGID4INST__MASK;
+}
+
+#define REG_A4XX_VFD_CONTROL_2                                 0x00002202
+
+#define REG_A4XX_VFD_CONTROL_3                                 0x00002203
+
+#define REG_A4XX_VFD_CONTROL_4                                 0x00002204
+
+#define REG_A4XX_VFD_INDEX_OFFSET                              0x00002208
+
+static inline uint32_t REG_A4XX_VFD_FETCH(uint32_t i0) { return 0x0000220a + 0x4*i0; }
+
+static inline uint32_t REG_A4XX_VFD_FETCH_INSTR_0(uint32_t i0) { return 0x0000220a + 0x4*i0; }
+#define A4XX_VFD_FETCH_INSTR_0_FETCHSIZE__MASK                 0x0000007f
+#define A4XX_VFD_FETCH_INSTR_0_FETCHSIZE__SHIFT                        0
+static inline uint32_t A4XX_VFD_FETCH_INSTR_0_FETCHSIZE(uint32_t val)
+{
+       return ((val) << A4XX_VFD_FETCH_INSTR_0_FETCHSIZE__SHIFT) & A4XX_VFD_FETCH_INSTR_0_FETCHSIZE__MASK;
+}
+#define A4XX_VFD_FETCH_INSTR_0_BUFSTRIDE__MASK                 0x0001ff80
+#define A4XX_VFD_FETCH_INSTR_0_BUFSTRIDE__SHIFT                        7
+static inline uint32_t A4XX_VFD_FETCH_INSTR_0_BUFSTRIDE(uint32_t val)
+{
+       return ((val) << A4XX_VFD_FETCH_INSTR_0_BUFSTRIDE__SHIFT) & A4XX_VFD_FETCH_INSTR_0_BUFSTRIDE__MASK;
+}
+#define A4XX_VFD_FETCH_INSTR_0_SWITCHNEXT                      0x00080000
+#define A4XX_VFD_FETCH_INSTR_0_STEPRATE__MASK                  0xff000000
+#define A4XX_VFD_FETCH_INSTR_0_STEPRATE__SHIFT                 24
+static inline uint32_t A4XX_VFD_FETCH_INSTR_0_STEPRATE(uint32_t val)
+{
+       return ((val) << A4XX_VFD_FETCH_INSTR_0_STEPRATE__SHIFT) & A4XX_VFD_FETCH_INSTR_0_STEPRATE__MASK;
+}
+
+static inline uint32_t REG_A4XX_VFD_FETCH_INSTR_1(uint32_t i0) { return 0x0000220b + 0x4*i0; }
+
+static inline uint32_t REG_A4XX_VFD_FETCH_INSTR_2(uint32_t i0) { return 0x0000220c + 0x4*i0; }
+#define A4XX_VFD_FETCH_INSTR_2_SIZE__MASK                      0xfffffff0
+#define A4XX_VFD_FETCH_INSTR_2_SIZE__SHIFT                     4
+static inline uint32_t A4XX_VFD_FETCH_INSTR_2_SIZE(uint32_t val)
+{
+       return ((val >> 4) << A4XX_VFD_FETCH_INSTR_2_SIZE__SHIFT) & A4XX_VFD_FETCH_INSTR_2_SIZE__MASK;
+}
+
+static inline uint32_t REG_A4XX_VFD_FETCH_INSTR_3(uint32_t i0) { return 0x0000220d + 0x4*i0; }
+
+static inline uint32_t REG_A4XX_VFD_DECODE(uint32_t i0) { return 0x0000228a + 0x1*i0; }
+
+static inline uint32_t REG_A4XX_VFD_DECODE_INSTR(uint32_t i0) { return 0x0000228a + 0x1*i0; }
+#define A4XX_VFD_DECODE_INSTR_WRITEMASK__MASK                  0x0000000f
+#define A4XX_VFD_DECODE_INSTR_WRITEMASK__SHIFT                 0
+static inline uint32_t A4XX_VFD_DECODE_INSTR_WRITEMASK(uint32_t val)
+{
+       return ((val) << A4XX_VFD_DECODE_INSTR_WRITEMASK__SHIFT) & A4XX_VFD_DECODE_INSTR_WRITEMASK__MASK;
+}
+#define A4XX_VFD_DECODE_INSTR_CONSTFILL                                0x00000010
+#define A4XX_VFD_DECODE_INSTR_FORMAT__MASK                     0x00000fc0
+#define A4XX_VFD_DECODE_INSTR_FORMAT__SHIFT                    6
+static inline uint32_t A4XX_VFD_DECODE_INSTR_FORMAT(enum a4xx_vtx_fmt val)
+{
+       return ((val) << A4XX_VFD_DECODE_INSTR_FORMAT__SHIFT) & A4XX_VFD_DECODE_INSTR_FORMAT__MASK;
+}
+#define A4XX_VFD_DECODE_INSTR_REGID__MASK                      0x000ff000
+#define A4XX_VFD_DECODE_INSTR_REGID__SHIFT                     12
+static inline uint32_t A4XX_VFD_DECODE_INSTR_REGID(uint32_t val)
+{
+       return ((val) << A4XX_VFD_DECODE_INSTR_REGID__SHIFT) & A4XX_VFD_DECODE_INSTR_REGID__MASK;
+}
+#define A4XX_VFD_DECODE_INSTR_SWAP__MASK                       0x00c00000
+#define A4XX_VFD_DECODE_INSTR_SWAP__SHIFT                      22
+static inline uint32_t A4XX_VFD_DECODE_INSTR_SWAP(enum a3xx_color_swap val)
+{
+       return ((val) << A4XX_VFD_DECODE_INSTR_SWAP__SHIFT) & A4XX_VFD_DECODE_INSTR_SWAP__MASK;
+}
+#define A4XX_VFD_DECODE_INSTR_SHIFTCNT__MASK                   0x1f000000
+#define A4XX_VFD_DECODE_INSTR_SHIFTCNT__SHIFT                  24
+static inline uint32_t A4XX_VFD_DECODE_INSTR_SHIFTCNT(uint32_t val)
+{
+       return ((val) << A4XX_VFD_DECODE_INSTR_SHIFTCNT__SHIFT) & A4XX_VFD_DECODE_INSTR_SHIFTCNT__MASK;
+}
+#define A4XX_VFD_DECODE_INSTR_LASTCOMPVALID                    0x20000000
+#define A4XX_VFD_DECODE_INSTR_SWITCHNEXT                       0x40000000
+
+#define REG_A4XX_TPL1_DEBUG_ECO_CONTROL                                0x00000f00
+
+#define REG_A4XX_TPL1_PERFCTR_TP_SEL_7                         0x00000f0b
+
+#define REG_A4XX_TPL1_TP_TEX_OFFSET                            0x00002380
+
+#define REG_A4XX_TPL1_TP_CS_TEXMEMOBJ_BASE_ADDR                        0x000023a6
+
+#define REG_A4XX_GRAS_TSE_STATUS                               0x00000c80
+
+#define REG_A4XX_GRAS_DEBUG_ECO_CONTROL                                0x00000c81
+
+#define REG_A4XX_GRAS_PERFCTR_TSE_SEL_0                                0x00000c88
+
+#define REG_A4XX_GRAS_PERFCTR_TSE_SEL_3                                0x00000c8b
+
+#define REG_A4XX_GRAS_CL_CLIP_CNTL                             0x00002000
+
+#define REG_A4XX_GRAS_CLEAR_CNTL                               0x00002003
+#define A4XX_GRAS_CLEAR_CNTL_NOT_FASTCLEAR                     0x00000001
+
+#define REG_A4XX_GRAS_CL_GB_CLIP_ADJ                           0x00002004
+#define A4XX_GRAS_CL_GB_CLIP_ADJ_HORZ__MASK                    0x000003ff
+#define A4XX_GRAS_CL_GB_CLIP_ADJ_HORZ__SHIFT                   0
+static inline uint32_t A4XX_GRAS_CL_GB_CLIP_ADJ_HORZ(uint32_t val)
+{
+       return ((val) << A4XX_GRAS_CL_GB_CLIP_ADJ_HORZ__SHIFT) & A4XX_GRAS_CL_GB_CLIP_ADJ_HORZ__MASK;
+}
+#define A4XX_GRAS_CL_GB_CLIP_ADJ_VERT__MASK                    0x000ffc00
+#define A4XX_GRAS_CL_GB_CLIP_ADJ_VERT__SHIFT                   10
+static inline uint32_t A4XX_GRAS_CL_GB_CLIP_ADJ_VERT(uint32_t val)
+{
+       return ((val) << A4XX_GRAS_CL_GB_CLIP_ADJ_VERT__SHIFT) & A4XX_GRAS_CL_GB_CLIP_ADJ_VERT__MASK;
+}
+
+#define REG_A4XX_GRAS_CL_VPORT_XOFFSET_0                       0x00002008
+#define A4XX_GRAS_CL_VPORT_XOFFSET_0__MASK                     0xffffffff
+#define A4XX_GRAS_CL_VPORT_XOFFSET_0__SHIFT                    0
+static inline uint32_t A4XX_GRAS_CL_VPORT_XOFFSET_0(float val)
+{
+       return ((fui(val)) << A4XX_GRAS_CL_VPORT_XOFFSET_0__SHIFT) & A4XX_GRAS_CL_VPORT_XOFFSET_0__MASK;
+}
+
+#define REG_A4XX_GRAS_CL_VPORT_XSCALE_0                                0x00002009
+#define A4XX_GRAS_CL_VPORT_XSCALE_0__MASK                      0xffffffff
+#define A4XX_GRAS_CL_VPORT_XSCALE_0__SHIFT                     0
+static inline uint32_t A4XX_GRAS_CL_VPORT_XSCALE_0(float val)
+{
+       return ((fui(val)) << A4XX_GRAS_CL_VPORT_XSCALE_0__SHIFT) & A4XX_GRAS_CL_VPORT_XSCALE_0__MASK;
+}
+
+#define REG_A4XX_GRAS_CL_VPORT_YOFFSET_0                       0x0000200a
+#define A4XX_GRAS_CL_VPORT_YOFFSET_0__MASK                     0xffffffff
+#define A4XX_GRAS_CL_VPORT_YOFFSET_0__SHIFT                    0
+static inline uint32_t A4XX_GRAS_CL_VPORT_YOFFSET_0(float val)
+{
+       return ((fui(val)) << A4XX_GRAS_CL_VPORT_YOFFSET_0__SHIFT) & A4XX_GRAS_CL_VPORT_YOFFSET_0__MASK;
+}
+
+#define REG_A4XX_GRAS_CL_VPORT_YSCALE_0                                0x0000200b
+#define A4XX_GRAS_CL_VPORT_YSCALE_0__MASK                      0xffffffff
+#define A4XX_GRAS_CL_VPORT_YSCALE_0__SHIFT                     0
+static inline uint32_t A4XX_GRAS_CL_VPORT_YSCALE_0(float val)
+{
+       return ((fui(val)) << A4XX_GRAS_CL_VPORT_YSCALE_0__SHIFT) & A4XX_GRAS_CL_VPORT_YSCALE_0__MASK;
+}
+
+#define REG_A4XX_GRAS_CL_VPORT_ZOFFSET_0                       0x0000200c
+#define A4XX_GRAS_CL_VPORT_ZOFFSET_0__MASK                     0xffffffff
+#define A4XX_GRAS_CL_VPORT_ZOFFSET_0__SHIFT                    0
+static inline uint32_t A4XX_GRAS_CL_VPORT_ZOFFSET_0(float val)
+{
+       return ((fui(val)) << A4XX_GRAS_CL_VPORT_ZOFFSET_0__SHIFT) & A4XX_GRAS_CL_VPORT_ZOFFSET_0__MASK;
+}
+
+#define REG_A4XX_GRAS_CL_VPORT_ZSCALE_0                                0x0000200d
+#define A4XX_GRAS_CL_VPORT_ZSCALE_0__MASK                      0xffffffff
+#define A4XX_GRAS_CL_VPORT_ZSCALE_0__SHIFT                     0
+static inline uint32_t A4XX_GRAS_CL_VPORT_ZSCALE_0(float val)
+{
+       return ((fui(val)) << A4XX_GRAS_CL_VPORT_ZSCALE_0__SHIFT) & A4XX_GRAS_CL_VPORT_ZSCALE_0__MASK;
+}
+
+#define REG_A4XX_GRAS_SU_POINT_MINMAX                          0x00002070
+#define A4XX_GRAS_SU_POINT_MINMAX_MIN__MASK                    0x0000ffff
+#define A4XX_GRAS_SU_POINT_MINMAX_MIN__SHIFT                   0
+static inline uint32_t A4XX_GRAS_SU_POINT_MINMAX_MIN(float val)
+{
+       return ((((uint32_t)(val * 16.0))) << A4XX_GRAS_SU_POINT_MINMAX_MIN__SHIFT) & A4XX_GRAS_SU_POINT_MINMAX_MIN__MASK;
+}
+#define A4XX_GRAS_SU_POINT_MINMAX_MAX__MASK                    0xffff0000
+#define A4XX_GRAS_SU_POINT_MINMAX_MAX__SHIFT                   16
+static inline uint32_t A4XX_GRAS_SU_POINT_MINMAX_MAX(float val)
+{
+       return ((((uint32_t)(val * 16.0))) << A4XX_GRAS_SU_POINT_MINMAX_MAX__SHIFT) & A4XX_GRAS_SU_POINT_MINMAX_MAX__MASK;
+}
+
+#define REG_A4XX_GRAS_SU_POINT_SIZE                            0x00002071
+#define A4XX_GRAS_SU_POINT_SIZE__MASK                          0xffffffff
+#define A4XX_GRAS_SU_POINT_SIZE__SHIFT                         0
+static inline uint32_t A4XX_GRAS_SU_POINT_SIZE(float val)
+{
+       return ((((int32_t)(val * 16.0))) << A4XX_GRAS_SU_POINT_SIZE__SHIFT) & A4XX_GRAS_SU_POINT_SIZE__MASK;
+}
+
+#define REG_A4XX_GRAS_ALPHA_CONTROL                            0x00002073
+#define A4XX_GRAS_ALPHA_CONTROL_ALPHA_TEST_ENABLE              0x00000004
+
+#define REG_A4XX_GRAS_SU_POLY_OFFSET_SCALE                     0x00002074
+#define A4XX_GRAS_SU_POLY_OFFSET_SCALE__MASK                   0xffffffff
+#define A4XX_GRAS_SU_POLY_OFFSET_SCALE__SHIFT                  0
+static inline uint32_t A4XX_GRAS_SU_POLY_OFFSET_SCALE(float val)
+{
+       return ((fui(val)) << A4XX_GRAS_SU_POLY_OFFSET_SCALE__SHIFT) & A4XX_GRAS_SU_POLY_OFFSET_SCALE__MASK;
+}
+
+#define REG_A4XX_GRAS_SU_POLY_OFFSET_OFFSET                    0x00002075
+#define A4XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK                  0xffffffff
+#define A4XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT                 0
+static inline uint32_t A4XX_GRAS_SU_POLY_OFFSET_OFFSET(float val)
+{
+       return ((fui(val)) << A4XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT) & A4XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK;
+}
+
+#define REG_A4XX_GRAS_SC_EXTENT_WINDOW_TL                      0x0000209f
+
+#define REG_A4XX_GRAS_SC_SCREEN_SCISSOR_TL                     0x0000207c
+#define A4XX_GRAS_SC_SCREEN_SCISSOR_TL_WINDOW_OFFSET_DISABLE   0x80000000
+#define A4XX_GRAS_SC_SCREEN_SCISSOR_TL_X__MASK                 0x00007fff
+#define A4XX_GRAS_SC_SCREEN_SCISSOR_TL_X__SHIFT                        0
+static inline uint32_t A4XX_GRAS_SC_SCREEN_SCISSOR_TL_X(uint32_t val)
+{
+       return ((val) << A4XX_GRAS_SC_SCREEN_SCISSOR_TL_X__SHIFT) & A4XX_GRAS_SC_SCREEN_SCISSOR_TL_X__MASK;
+}
+#define A4XX_GRAS_SC_SCREEN_SCISSOR_TL_Y__MASK                 0x7fff0000
+#define A4XX_GRAS_SC_SCREEN_SCISSOR_TL_Y__SHIFT                        16
+static inline uint32_t A4XX_GRAS_SC_SCREEN_SCISSOR_TL_Y(uint32_t val)
+{
+       return ((val) << A4XX_GRAS_SC_SCREEN_SCISSOR_TL_Y__SHIFT) & A4XX_GRAS_SC_SCREEN_SCISSOR_TL_Y__MASK;
+}
+
+#define REG_A4XX_GRAS_SC_SCREEN_SCISSOR_BR                     0x0000207d
+#define A4XX_GRAS_SC_SCREEN_SCISSOR_BR_WINDOW_OFFSET_DISABLE   0x80000000
+#define A4XX_GRAS_SC_SCREEN_SCISSOR_BR_X__MASK                 0x00007fff
+#define A4XX_GRAS_SC_SCREEN_SCISSOR_BR_X__SHIFT                        0
+static inline uint32_t A4XX_GRAS_SC_SCREEN_SCISSOR_BR_X(uint32_t val)
+{
+       return ((val) << A4XX_GRAS_SC_SCREEN_SCISSOR_BR_X__SHIFT) & A4XX_GRAS_SC_SCREEN_SCISSOR_BR_X__MASK;
+}
+#define A4XX_GRAS_SC_SCREEN_SCISSOR_BR_Y__MASK                 0x7fff0000
+#define A4XX_GRAS_SC_SCREEN_SCISSOR_BR_Y__SHIFT                        16
+static inline uint32_t A4XX_GRAS_SC_SCREEN_SCISSOR_BR_Y(uint32_t val)
+{
+       return ((val) << A4XX_GRAS_SC_SCREEN_SCISSOR_BR_Y__SHIFT) & A4XX_GRAS_SC_SCREEN_SCISSOR_BR_Y__MASK;
+}
+
+#define REG_A4XX_GRAS_SC_WINDOW_SCISSOR_BR                     0x0000209c
+#define A4XX_GRAS_SC_WINDOW_SCISSOR_BR_WINDOW_OFFSET_DISABLE   0x80000000
+#define A4XX_GRAS_SC_WINDOW_SCISSOR_BR_X__MASK                 0x00007fff
+#define A4XX_GRAS_SC_WINDOW_SCISSOR_BR_X__SHIFT                        0
+static inline uint32_t A4XX_GRAS_SC_WINDOW_SCISSOR_BR_X(uint32_t val)
+{
+       return ((val) << A4XX_GRAS_SC_WINDOW_SCISSOR_BR_X__SHIFT) & A4XX_GRAS_SC_WINDOW_SCISSOR_BR_X__MASK;
+}
+#define A4XX_GRAS_SC_WINDOW_SCISSOR_BR_Y__MASK                 0x7fff0000
+#define A4XX_GRAS_SC_WINDOW_SCISSOR_BR_Y__SHIFT                        16
+static inline uint32_t A4XX_GRAS_SC_WINDOW_SCISSOR_BR_Y(uint32_t val)
+{
+       return ((val) << A4XX_GRAS_SC_WINDOW_SCISSOR_BR_Y__SHIFT) & A4XX_GRAS_SC_WINDOW_SCISSOR_BR_Y__MASK;
+}
+
+#define REG_A4XX_GRAS_SC_WINDOW_SCISSOR_TL                     0x0000209d
+#define A4XX_GRAS_SC_WINDOW_SCISSOR_TL_WINDOW_OFFSET_DISABLE   0x80000000
+#define A4XX_GRAS_SC_WINDOW_SCISSOR_TL_X__MASK                 0x00007fff
+#define A4XX_GRAS_SC_WINDOW_SCISSOR_TL_X__SHIFT                        0
+static inline uint32_t A4XX_GRAS_SC_WINDOW_SCISSOR_TL_X(uint32_t val)
+{
+       return ((val) << A4XX_GRAS_SC_WINDOW_SCISSOR_TL_X__SHIFT) & A4XX_GRAS_SC_WINDOW_SCISSOR_TL_X__MASK;
+}
+#define A4XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__MASK                 0x7fff0000
+#define A4XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__SHIFT                        16
+static inline uint32_t A4XX_GRAS_SC_WINDOW_SCISSOR_TL_Y(uint32_t val)
+{
+       return ((val) << A4XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__SHIFT) & A4XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__MASK;
+}
+
+#define REG_A4XX_GRAS_DEPTH_CONTROL                            0x00002077
+#define A4XX_GRAS_DEPTH_CONTROL_FORMAT__MASK                   0x00000003
+#define A4XX_GRAS_DEPTH_CONTROL_FORMAT__SHIFT                  0
+static inline uint32_t A4XX_GRAS_DEPTH_CONTROL_FORMAT(enum a4xx_depth_format val)
+{
+       return ((val) << A4XX_GRAS_DEPTH_CONTROL_FORMAT__SHIFT) & A4XX_GRAS_DEPTH_CONTROL_FORMAT__MASK;
+}
+
+#define REG_A4XX_GRAS_SU_MODE_CONTROL                          0x00002078
+#define A4XX_GRAS_SU_MODE_CONTROL_CULL_FRONT                   0x00000001
+#define A4XX_GRAS_SU_MODE_CONTROL_CULL_BACK                    0x00000002
+#define A4XX_GRAS_SU_MODE_CONTROL_FRONT_CW                     0x00000004
+#define A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK          0x000007f8
+#define A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT         3
+static inline uint32_t A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH(float val)
+{
+       return ((((int32_t)(val * 4.0))) << A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT) & A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK;
+}
+#define A4XX_GRAS_SU_MODE_CONTROL_POLY_OFFSET                  0x00000800
+#define A4XX_GRAS_SU_MODE_CONTROL_RENDERING_PASS               0x00100000
+
+#define REG_A4XX_GRAS_SC_CONTROL                               0x0000207b
+#define A4XX_GRAS_SC_CONTROL_RENDER_MODE__MASK                 0x0000000c
+#define A4XX_GRAS_SC_CONTROL_RENDER_MODE__SHIFT                        2
+static inline uint32_t A4XX_GRAS_SC_CONTROL_RENDER_MODE(enum a3xx_render_mode val)
+{
+       return ((val) << A4XX_GRAS_SC_CONTROL_RENDER_MODE__SHIFT) & A4XX_GRAS_SC_CONTROL_RENDER_MODE__MASK;
+}
+#define A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__MASK                        0x00000380
+#define A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__SHIFT               7
+static inline uint32_t A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES(uint32_t val)
+{
+       return ((val) << A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__SHIFT) & A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__MASK;
+}
+#define A4XX_GRAS_SC_CONTROL_MSAA_DISABLE                      0x00000800
+#define A4XX_GRAS_SC_CONTROL_RASTER_MODE__MASK                 0x0000f000
+#define A4XX_GRAS_SC_CONTROL_RASTER_MODE__SHIFT                        12
+static inline uint32_t A4XX_GRAS_SC_CONTROL_RASTER_MODE(uint32_t val)
+{
+       return ((val) << A4XX_GRAS_SC_CONTROL_RASTER_MODE__SHIFT) & A4XX_GRAS_SC_CONTROL_RASTER_MODE__MASK;
+}
+
+#define REG_A4XX_UCHE_CACHE_MODE_CONTROL                       0x00000e80
+
+#define REG_A4XX_UCHE_TRAP_BASE_LO                             0x00000e83
+
+#define REG_A4XX_UCHE_TRAP_BASE_HI                             0x00000e84
+
+#define REG_A4XX_UCHE_CACHE_STATUS                             0x00000e88
+
+#define REG_A4XX_UCHE_INVALIDATE0                              0x00000e8a
+
+#define REG_A4XX_UCHE_INVALIDATE1                              0x00000e8b
+
+#define REG_A4XX_UCHE_CACHE_WAYS_VFD                           0x00000e8c
+
+#define REG_A4XX_UCHE_PERFCTR_UCHE_SEL_7                       0x00000e95
+
+#define REG_A4XX_HLSQ_TIMEOUT_THRESHOLD                                0x00000e00
+
+#define REG_A4XX_HLSQ_DEBUG_ECO_CONTROL                                0x00000e04
+
+#define REG_A4XX_HLSQ_PERF_PIPE_MASK                           0x00000e0e
+
+#define REG_A4XX_HLSQ_CONTROL_0_REG                            0x000023c0
+#define A4XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE__MASK             0x00000010
+#define A4XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE__SHIFT            4
+static inline uint32_t A4XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE(enum a3xx_threadsize val)
+{
+       return ((val) << A4XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE__SHIFT) & A4XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE__MASK;
+}
+#define A4XX_HLSQ_CONTROL_0_REG_FSSUPERTHREADENABLE            0x00000040
+#define A4XX_HLSQ_CONTROL_0_REG_SPSHADERRESTART                        0x00000200
+#define A4XX_HLSQ_CONTROL_0_REG_RESERVED2                      0x00000400
+#define A4XX_HLSQ_CONTROL_0_REG_CHUNKDISABLE                   0x04000000
+#define A4XX_HLSQ_CONTROL_0_REG_CONSTMODE__MASK                        0x08000000
+#define A4XX_HLSQ_CONTROL_0_REG_CONSTMODE__SHIFT               27
+static inline uint32_t A4XX_HLSQ_CONTROL_0_REG_CONSTMODE(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_CONTROL_0_REG_CONSTMODE__SHIFT) & A4XX_HLSQ_CONTROL_0_REG_CONSTMODE__MASK;
+}
+#define A4XX_HLSQ_CONTROL_0_REG_LAZYUPDATEDISABLE              0x10000000
+#define A4XX_HLSQ_CONTROL_0_REG_SPCONSTFULLUPDATE              0x20000000
+#define A4XX_HLSQ_CONTROL_0_REG_TPFULLUPDATE                   0x40000000
+#define A4XX_HLSQ_CONTROL_0_REG_SINGLECONTEXT                  0x80000000
+
+#define REG_A4XX_HLSQ_CONTROL_1_REG                            0x000023c1
+#define A4XX_HLSQ_CONTROL_1_REG_VSTHREADSIZE__MASK             0x00000040
+#define A4XX_HLSQ_CONTROL_1_REG_VSTHREADSIZE__SHIFT            6
+static inline uint32_t A4XX_HLSQ_CONTROL_1_REG_VSTHREADSIZE(enum a3xx_threadsize val)
+{
+       return ((val) << A4XX_HLSQ_CONTROL_1_REG_VSTHREADSIZE__SHIFT) & A4XX_HLSQ_CONTROL_1_REG_VSTHREADSIZE__MASK;
+}
+#define A4XX_HLSQ_CONTROL_1_REG_VSSUPERTHREADENABLE            0x00000100
+#define A4XX_HLSQ_CONTROL_1_REG_RESERVED1                      0x00000200
+#define A4XX_HLSQ_CONTROL_1_REG_ZWCOORD                                0x02000000
+
+#define REG_A4XX_HLSQ_CONTROL_2_REG                            0x000023c2
+#define A4XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD__MASK       0xfc000000
+#define A4XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD__SHIFT      26
+static inline uint32_t A4XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD__SHIFT) & A4XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD__MASK;
+}
+
+#define REG_A4XX_HLSQ_CONTROL_3_REG                            0x000023c3
+#define A4XX_HLSQ_CONTROL_3_REG_REGID__MASK                    0x000000ff
+#define A4XX_HLSQ_CONTROL_3_REG_REGID__SHIFT                   0
+static inline uint32_t A4XX_HLSQ_CONTROL_3_REG_REGID(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_CONTROL_3_REG_REGID__SHIFT) & A4XX_HLSQ_CONTROL_3_REG_REGID__MASK;
+}
+
+#define REG_A4XX_HLSQ_VS_CONTROL_REG                           0x000023c5
+#define A4XX_HLSQ_VS_CONTROL_REG_CONSTLENGTH__MASK             0x000000ff
+#define A4XX_HLSQ_VS_CONTROL_REG_CONSTLENGTH__SHIFT            0
+static inline uint32_t A4XX_HLSQ_VS_CONTROL_REG_CONSTLENGTH(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_VS_CONTROL_REG_CONSTLENGTH__SHIFT) & A4XX_HLSQ_VS_CONTROL_REG_CONSTLENGTH__MASK;
+}
+#define A4XX_HLSQ_VS_CONTROL_REG_CONSTOBJECTOFFSET__MASK       0x0000ff00
+#define A4XX_HLSQ_VS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT      8
+static inline uint32_t A4XX_HLSQ_VS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_VS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A4XX_HLSQ_VS_CONTROL_REG_CONSTOBJECTOFFSET__MASK;
+}
+#define A4XX_HLSQ_VS_CONTROL_REG_SHADEROBJOFFSET__MASK         0x00fe0000
+#define A4XX_HLSQ_VS_CONTROL_REG_SHADEROBJOFFSET__SHIFT                17
+static inline uint32_t A4XX_HLSQ_VS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_VS_CONTROL_REG_SHADEROBJOFFSET__SHIFT) & A4XX_HLSQ_VS_CONTROL_REG_SHADEROBJOFFSET__MASK;
+}
+#define A4XX_HLSQ_VS_CONTROL_REG_INSTRLENGTH__MASK             0xff000000
+#define A4XX_HLSQ_VS_CONTROL_REG_INSTRLENGTH__SHIFT            24
+static inline uint32_t A4XX_HLSQ_VS_CONTROL_REG_INSTRLENGTH(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_VS_CONTROL_REG_INSTRLENGTH__SHIFT) & A4XX_HLSQ_VS_CONTROL_REG_INSTRLENGTH__MASK;
+}
+
+#define REG_A4XX_HLSQ_FS_CONTROL_REG                           0x000023c6
+#define A4XX_HLSQ_FS_CONTROL_REG_CONSTLENGTH__MASK             0x000000ff
+#define A4XX_HLSQ_FS_CONTROL_REG_CONSTLENGTH__SHIFT            0
+static inline uint32_t A4XX_HLSQ_FS_CONTROL_REG_CONSTLENGTH(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_FS_CONTROL_REG_CONSTLENGTH__SHIFT) & A4XX_HLSQ_FS_CONTROL_REG_CONSTLENGTH__MASK;
+}
+#define A4XX_HLSQ_FS_CONTROL_REG_CONSTOBJECTOFFSET__MASK       0x0000ff00
+#define A4XX_HLSQ_FS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT      8
+static inline uint32_t A4XX_HLSQ_FS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_FS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A4XX_HLSQ_FS_CONTROL_REG_CONSTOBJECTOFFSET__MASK;
+}
+#define A4XX_HLSQ_FS_CONTROL_REG_SHADEROBJOFFSET__MASK         0x00fe0000
+#define A4XX_HLSQ_FS_CONTROL_REG_SHADEROBJOFFSET__SHIFT                17
+static inline uint32_t A4XX_HLSQ_FS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_FS_CONTROL_REG_SHADEROBJOFFSET__SHIFT) & A4XX_HLSQ_FS_CONTROL_REG_SHADEROBJOFFSET__MASK;
+}
+#define A4XX_HLSQ_FS_CONTROL_REG_INSTRLENGTH__MASK             0xff000000
+#define A4XX_HLSQ_FS_CONTROL_REG_INSTRLENGTH__SHIFT            24
+static inline uint32_t A4XX_HLSQ_FS_CONTROL_REG_INSTRLENGTH(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_FS_CONTROL_REG_INSTRLENGTH__SHIFT) & A4XX_HLSQ_FS_CONTROL_REG_INSTRLENGTH__MASK;
+}
+
+#define REG_A4XX_HLSQ_HS_CONTROL_REG                           0x000023c7
+#define A4XX_HLSQ_HS_CONTROL_REG_CONSTLENGTH__MASK             0x000000ff
+#define A4XX_HLSQ_HS_CONTROL_REG_CONSTLENGTH__SHIFT            0
+static inline uint32_t A4XX_HLSQ_HS_CONTROL_REG_CONSTLENGTH(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_HS_CONTROL_REG_CONSTLENGTH__SHIFT) & A4XX_HLSQ_HS_CONTROL_REG_CONSTLENGTH__MASK;
+}
+#define A4XX_HLSQ_HS_CONTROL_REG_CONSTOBJECTOFFSET__MASK       0x0000ff00
+#define A4XX_HLSQ_HS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT      8
+static inline uint32_t A4XX_HLSQ_HS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_HS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A4XX_HLSQ_HS_CONTROL_REG_CONSTOBJECTOFFSET__MASK;
+}
+#define A4XX_HLSQ_HS_CONTROL_REG_SHADEROBJOFFSET__MASK         0x00fe0000
+#define A4XX_HLSQ_HS_CONTROL_REG_SHADEROBJOFFSET__SHIFT                17
+static inline uint32_t A4XX_HLSQ_HS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_HS_CONTROL_REG_SHADEROBJOFFSET__SHIFT) & A4XX_HLSQ_HS_CONTROL_REG_SHADEROBJOFFSET__MASK;
+}
+#define A4XX_HLSQ_HS_CONTROL_REG_INSTRLENGTH__MASK             0xff000000
+#define A4XX_HLSQ_HS_CONTROL_REG_INSTRLENGTH__SHIFT            24
+static inline uint32_t A4XX_HLSQ_HS_CONTROL_REG_INSTRLENGTH(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_HS_CONTROL_REG_INSTRLENGTH__SHIFT) & A4XX_HLSQ_HS_CONTROL_REG_INSTRLENGTH__MASK;
+}
+
+#define REG_A4XX_HLSQ_DS_CONTROL_REG                           0x000023c8
+#define A4XX_HLSQ_DS_CONTROL_REG_CONSTLENGTH__MASK             0x000000ff
+#define A4XX_HLSQ_DS_CONTROL_REG_CONSTLENGTH__SHIFT            0
+static inline uint32_t A4XX_HLSQ_DS_CONTROL_REG_CONSTLENGTH(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_DS_CONTROL_REG_CONSTLENGTH__SHIFT) & A4XX_HLSQ_DS_CONTROL_REG_CONSTLENGTH__MASK;
+}
+#define A4XX_HLSQ_DS_CONTROL_REG_CONSTOBJECTOFFSET__MASK       0x0000ff00
+#define A4XX_HLSQ_DS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT      8
+static inline uint32_t A4XX_HLSQ_DS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_DS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A4XX_HLSQ_DS_CONTROL_REG_CONSTOBJECTOFFSET__MASK;
+}
+#define A4XX_HLSQ_DS_CONTROL_REG_SHADEROBJOFFSET__MASK         0x00fe0000
+#define A4XX_HLSQ_DS_CONTROL_REG_SHADEROBJOFFSET__SHIFT                17
+static inline uint32_t A4XX_HLSQ_DS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_DS_CONTROL_REG_SHADEROBJOFFSET__SHIFT) & A4XX_HLSQ_DS_CONTROL_REG_SHADEROBJOFFSET__MASK;
+}
+#define A4XX_HLSQ_DS_CONTROL_REG_INSTRLENGTH__MASK             0xff000000
+#define A4XX_HLSQ_DS_CONTROL_REG_INSTRLENGTH__SHIFT            24
+static inline uint32_t A4XX_HLSQ_DS_CONTROL_REG_INSTRLENGTH(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_DS_CONTROL_REG_INSTRLENGTH__SHIFT) & A4XX_HLSQ_DS_CONTROL_REG_INSTRLENGTH__MASK;
+}
+
+#define REG_A4XX_HLSQ_GS_CONTROL_REG                           0x000023c9
+#define A4XX_HLSQ_GS_CONTROL_REG_CONSTLENGTH__MASK             0x000000ff
+#define A4XX_HLSQ_GS_CONTROL_REG_CONSTLENGTH__SHIFT            0
+static inline uint32_t A4XX_HLSQ_GS_CONTROL_REG_CONSTLENGTH(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_GS_CONTROL_REG_CONSTLENGTH__SHIFT) & A4XX_HLSQ_GS_CONTROL_REG_CONSTLENGTH__MASK;
+}
+#define A4XX_HLSQ_GS_CONTROL_REG_CONSTOBJECTOFFSET__MASK       0x0000ff00
+#define A4XX_HLSQ_GS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT      8
+static inline uint32_t A4XX_HLSQ_GS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_GS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A4XX_HLSQ_GS_CONTROL_REG_CONSTOBJECTOFFSET__MASK;
+}
+#define A4XX_HLSQ_GS_CONTROL_REG_SHADEROBJOFFSET__MASK         0x00fe0000
+#define A4XX_HLSQ_GS_CONTROL_REG_SHADEROBJOFFSET__SHIFT                17
+static inline uint32_t A4XX_HLSQ_GS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_GS_CONTROL_REG_SHADEROBJOFFSET__SHIFT) & A4XX_HLSQ_GS_CONTROL_REG_SHADEROBJOFFSET__MASK;
+}
+#define A4XX_HLSQ_GS_CONTROL_REG_INSTRLENGTH__MASK             0xff000000
+#define A4XX_HLSQ_GS_CONTROL_REG_INSTRLENGTH__SHIFT            24
+static inline uint32_t A4XX_HLSQ_GS_CONTROL_REG_INSTRLENGTH(uint32_t val)
+{
+       return ((val) << A4XX_HLSQ_GS_CONTROL_REG_INSTRLENGTH__SHIFT) & A4XX_HLSQ_GS_CONTROL_REG_INSTRLENGTH__MASK;
+}
+
+#define REG_A4XX_HLSQ_UPDATE_CONTROL                           0x000023db
+
+#define REG_A4XX_PC_BINNING_COMMAND                            0x00000d00
+#define A4XX_PC_BINNING_COMMAND_BINNING_ENABLE                 0x00000001
+
+#define REG_A4XX_PC_DRAWCALL_SETUP_OVERRIDE                    0x00000d0c
+
+#define REG_A4XX_PC_PERFCTR_PC_SEL_0                           0x00000d10
+
+#define REG_A4XX_PC_PERFCTR_PC_SEL_7                           0x00000d17
+
+#define REG_A4XX_PC_BIN_BASE                                   0x000021c0
+
+#define REG_A4XX_PC_PRIM_VTX_CNTL                              0x000021c4
+#define A4XX_PC_PRIM_VTX_CNTL_VAROUT                           0x00000001
+#define A4XX_PC_PRIM_VTX_CNTL_PROVOKING_VTX_LAST               0x02000000
+#define A4XX_PC_PRIM_VTX_CNTL_PSIZE                            0x04000000
+
+#define REG_A4XX_UNKNOWN_21C5                                  0x000021c5
+
+#define REG_A4XX_PC_RESTART_INDEX                              0x000021c6
+
+#define REG_A4XX_PC_GS_PARAM                                   0x000021e5
+
+#define REG_A4XX_PC_HS_PARAM                                   0x000021e7
+
+#define REG_A4XX_VBIF_VERSION                                  0x00003000
+
+#define REG_A4XX_VBIF_CLKON                                    0x00003001
+#define A4XX_VBIF_CLKON_FORCE_ON_TESTBUS                       0x00000001
+
+#define REG_A4XX_VBIF_ABIT_SORT                                        0x0000301c
+
+#define REG_A4XX_VBIF_ABIT_SORT_CONF                           0x0000301d
+
+#define REG_A4XX_VBIF_GATE_OFF_WRREQ_EN                                0x0000302a
+
+#define REG_A4XX_VBIF_IN_RD_LIM_CONF0                          0x0000302c
+
+#define REG_A4XX_VBIF_IN_RD_LIM_CONF1                          0x0000302d
+
+#define REG_A4XX_VBIF_IN_WR_LIM_CONF0                          0x00003030
+
+#define REG_A4XX_VBIF_IN_WR_LIM_CONF1                          0x00003031
+
+#define REG_A4XX_VBIF_ROUND_ROBIN_QOS_ARB                      0x00003049
+
+#define REG_A4XX_UNKNOWN_0CC5                                  0x00000cc5
+
+#define REG_A4XX_UNKNOWN_0CC6                                  0x00000cc6
+
+#define REG_A4XX_UNKNOWN_0D01                                  0x00000d01
+
+#define REG_A4XX_UNKNOWN_0E05                                  0x00000e05
+
+#define REG_A4XX_UNKNOWN_0E42                                  0x00000e42
+
+#define REG_A4XX_UNKNOWN_0EC2                                  0x00000ec2
+
+#define REG_A4XX_UNKNOWN_0EC3                                  0x00000ec3
+
+#define REG_A4XX_UNKNOWN_0F03                                  0x00000f03
+
+#define REG_A4XX_UNKNOWN_2001                                  0x00002001
+
+#define REG_A4XX_UNKNOWN_209B                                  0x0000209b
+
+#define REG_A4XX_UNKNOWN_20EF                                  0x000020ef
+
+#define REG_A4XX_UNKNOWN_20F0                                  0x000020f0
+
+#define REG_A4XX_UNKNOWN_20F1                                  0x000020f1
+
+#define REG_A4XX_UNKNOWN_20F2                                  0x000020f2
+
+#define REG_A4XX_UNKNOWN_20F3                                  0x000020f3
+
+#define REG_A4XX_UNKNOWN_20F4                                  0x000020f4
+
+#define REG_A4XX_UNKNOWN_20F5                                  0x000020f5
+
+#define REG_A4XX_UNKNOWN_20F6                                  0x000020f6
+
+#define REG_A4XX_UNKNOWN_20F7                                  0x000020f7
+
+#define REG_A4XX_UNKNOWN_2152                                  0x00002152
+
+#define REG_A4XX_UNKNOWN_2153                                  0x00002153
+
+#define REG_A4XX_UNKNOWN_2154                                  0x00002154
+
+#define REG_A4XX_UNKNOWN_2155                                  0x00002155
+
+#define REG_A4XX_UNKNOWN_2156                                  0x00002156
+
+#define REG_A4XX_UNKNOWN_2157                                  0x00002157
+
+#define REG_A4XX_UNKNOWN_21C3                                  0x000021c3
+
+#define REG_A4XX_UNKNOWN_21E6                                  0x000021e6
+
+#define REG_A4XX_UNKNOWN_2209                                  0x00002209
+
+#define REG_A4XX_UNKNOWN_22D7                                  0x000022d7
+
+#define REG_A4XX_UNKNOWN_2381                                  0x00002381
+
+#define REG_A4XX_UNKNOWN_23A0                                  0x000023a0
+
+#define REG_A4XX_TEX_SAMP_0                                    0x00000000
+#define A4XX_TEX_SAMP_0_XY_MAG__MASK                           0x00000006
+#define A4XX_TEX_SAMP_0_XY_MAG__SHIFT                          1
+static inline uint32_t A4XX_TEX_SAMP_0_XY_MAG(enum a4xx_tex_filter val)
+{
+       return ((val) << A4XX_TEX_SAMP_0_XY_MAG__SHIFT) & A4XX_TEX_SAMP_0_XY_MAG__MASK;
+}
+#define A4XX_TEX_SAMP_0_XY_MIN__MASK                           0x00000018
+#define A4XX_TEX_SAMP_0_XY_MIN__SHIFT                          3
+static inline uint32_t A4XX_TEX_SAMP_0_XY_MIN(enum a4xx_tex_filter val)
+{
+       return ((val) << A4XX_TEX_SAMP_0_XY_MIN__SHIFT) & A4XX_TEX_SAMP_0_XY_MIN__MASK;
+}
+#define A4XX_TEX_SAMP_0_WRAP_S__MASK                           0x000000e0
+#define A4XX_TEX_SAMP_0_WRAP_S__SHIFT                          5
+static inline uint32_t A4XX_TEX_SAMP_0_WRAP_S(enum a4xx_tex_clamp val)
+{
+       return ((val) << A4XX_TEX_SAMP_0_WRAP_S__SHIFT) & A4XX_TEX_SAMP_0_WRAP_S__MASK;
+}
+#define A4XX_TEX_SAMP_0_WRAP_T__MASK                           0x00000700
+#define A4XX_TEX_SAMP_0_WRAP_T__SHIFT                          8
+static inline uint32_t A4XX_TEX_SAMP_0_WRAP_T(enum a4xx_tex_clamp val)
+{
+       return ((val) << A4XX_TEX_SAMP_0_WRAP_T__SHIFT) & A4XX_TEX_SAMP_0_WRAP_T__MASK;
+}
+#define A4XX_TEX_SAMP_0_WRAP_R__MASK                           0x00003800
+#define A4XX_TEX_SAMP_0_WRAP_R__SHIFT                          11
+static inline uint32_t A4XX_TEX_SAMP_0_WRAP_R(enum a4xx_tex_clamp val)
+{
+       return ((val) << A4XX_TEX_SAMP_0_WRAP_R__SHIFT) & A4XX_TEX_SAMP_0_WRAP_R__MASK;
+}
+
+#define REG_A4XX_TEX_SAMP_1                                    0x00000001
+#define A4XX_TEX_SAMP_1_COMPARE_FUNC__MASK                     0x0000000e
+#define A4XX_TEX_SAMP_1_COMPARE_FUNC__SHIFT                    1
+static inline uint32_t A4XX_TEX_SAMP_1_COMPARE_FUNC(enum adreno_compare_func val)
+{
+       return ((val) << A4XX_TEX_SAMP_1_COMPARE_FUNC__SHIFT) & A4XX_TEX_SAMP_1_COMPARE_FUNC__MASK;
+}
+#define A4XX_TEX_SAMP_1_MAX_LOD__MASK                          0x000fff00
+#define A4XX_TEX_SAMP_1_MAX_LOD__SHIFT                         8
+static inline uint32_t A4XX_TEX_SAMP_1_MAX_LOD(float val)
+{
+       return ((((uint32_t)(val * 64.0))) << A4XX_TEX_SAMP_1_MAX_LOD__SHIFT) & A4XX_TEX_SAMP_1_MAX_LOD__MASK;
+}
+#define A4XX_TEX_SAMP_1_MIN_LOD__MASK                          0xfff00000
+#define A4XX_TEX_SAMP_1_MIN_LOD__SHIFT                         20
+static inline uint32_t A4XX_TEX_SAMP_1_MIN_LOD(float val)
+{
+       return ((((uint32_t)(val * 64.0))) << A4XX_TEX_SAMP_1_MIN_LOD__SHIFT) & A4XX_TEX_SAMP_1_MIN_LOD__MASK;
+}
+
+#define REG_A4XX_TEX_CONST_0                                   0x00000000
+#define A4XX_TEX_CONST_0_TILED                                 0x00000001
+#define A4XX_TEX_CONST_0_SWIZ_X__MASK                          0x00000070
+#define A4XX_TEX_CONST_0_SWIZ_X__SHIFT                         4
+static inline uint32_t A4XX_TEX_CONST_0_SWIZ_X(enum a4xx_tex_swiz val)
+{
+       return ((val) << A4XX_TEX_CONST_0_SWIZ_X__SHIFT) & A4XX_TEX_CONST_0_SWIZ_X__MASK;
+}
+#define A4XX_TEX_CONST_0_SWIZ_Y__MASK                          0x00000380
+#define A4XX_TEX_CONST_0_SWIZ_Y__SHIFT                         7
+static inline uint32_t A4XX_TEX_CONST_0_SWIZ_Y(enum a4xx_tex_swiz val)
+{
+       return ((val) << A4XX_TEX_CONST_0_SWIZ_Y__SHIFT) & A4XX_TEX_CONST_0_SWIZ_Y__MASK;
+}
+#define A4XX_TEX_CONST_0_SWIZ_Z__MASK                          0x00001c00
+#define A4XX_TEX_CONST_0_SWIZ_Z__SHIFT                         10
+static inline uint32_t A4XX_TEX_CONST_0_SWIZ_Z(enum a4xx_tex_swiz val)
+{
+       return ((val) << A4XX_TEX_CONST_0_SWIZ_Z__SHIFT) & A4XX_TEX_CONST_0_SWIZ_Z__MASK;
+}
+#define A4XX_TEX_CONST_0_SWIZ_W__MASK                          0x0000e000
+#define A4XX_TEX_CONST_0_SWIZ_W__SHIFT                         13
+static inline uint32_t A4XX_TEX_CONST_0_SWIZ_W(enum a4xx_tex_swiz val)
+{
+       return ((val) << A4XX_TEX_CONST_0_SWIZ_W__SHIFT) & A4XX_TEX_CONST_0_SWIZ_W__MASK;
+}
+#define A4XX_TEX_CONST_0_FMT__MASK                             0x1fc00000
+#define A4XX_TEX_CONST_0_FMT__SHIFT                            22
+static inline uint32_t A4XX_TEX_CONST_0_FMT(enum a4xx_tex_fmt val)
+{
+       return ((val) << A4XX_TEX_CONST_0_FMT__SHIFT) & A4XX_TEX_CONST_0_FMT__MASK;
+}
+#define A4XX_TEX_CONST_0_TYPE__MASK                            0x60000000
+#define A4XX_TEX_CONST_0_TYPE__SHIFT                           29
+static inline uint32_t A4XX_TEX_CONST_0_TYPE(enum a4xx_tex_type val)
+{
+       return ((val) << A4XX_TEX_CONST_0_TYPE__SHIFT) & A4XX_TEX_CONST_0_TYPE__MASK;
+}
+
+#define REG_A4XX_TEX_CONST_1                                   0x00000001
+#define A4XX_TEX_CONST_1_HEIGHT__MASK                          0x00007fff
+#define A4XX_TEX_CONST_1_HEIGHT__SHIFT                         0
+static inline uint32_t A4XX_TEX_CONST_1_HEIGHT(uint32_t val)
+{
+       return ((val) << A4XX_TEX_CONST_1_HEIGHT__SHIFT) & A4XX_TEX_CONST_1_HEIGHT__MASK;
+}
+#define A4XX_TEX_CONST_1_WIDTH__MASK                           0x1fff8000
+#define A4XX_TEX_CONST_1_WIDTH__SHIFT                          15
+static inline uint32_t A4XX_TEX_CONST_1_WIDTH(uint32_t val)
+{
+       return ((val) << A4XX_TEX_CONST_1_WIDTH__SHIFT) & A4XX_TEX_CONST_1_WIDTH__MASK;
+}
+
+#define REG_A4XX_TEX_CONST_2                                   0x00000002
+#define A4XX_TEX_CONST_2_PITCH__MASK                           0x3ffffe00
+#define A4XX_TEX_CONST_2_PITCH__SHIFT                          9
+static inline uint32_t A4XX_TEX_CONST_2_PITCH(uint32_t val)
+{
+       return ((val) << A4XX_TEX_CONST_2_PITCH__SHIFT) & A4XX_TEX_CONST_2_PITCH__MASK;
+}
+#define A4XX_TEX_CONST_2_SWAP__MASK                            0xc0000000
+#define A4XX_TEX_CONST_2_SWAP__SHIFT                           30
+static inline uint32_t A4XX_TEX_CONST_2_SWAP(enum a3xx_color_swap val)
+{
+       return ((val) << A4XX_TEX_CONST_2_SWAP__SHIFT) & A4XX_TEX_CONST_2_SWAP__MASK;
+}
+
+#define REG_A4XX_TEX_CONST_3                                   0x00000003
+#define A4XX_TEX_CONST_3_LAYERSZ__MASK                         0x0000000f
+#define A4XX_TEX_CONST_3_LAYERSZ__SHIFT                                0
+static inline uint32_t A4XX_TEX_CONST_3_LAYERSZ(uint32_t val)
+{
+       return ((val >> 12) << A4XX_TEX_CONST_3_LAYERSZ__SHIFT) & A4XX_TEX_CONST_3_LAYERSZ__MASK;
+}
+
+#define REG_A4XX_TEX_CONST_4                                   0x00000004
+#define A4XX_TEX_CONST_4_BASE__MASK                            0xffffffff
+#define A4XX_TEX_CONST_4_BASE__SHIFT                           0
+static inline uint32_t A4XX_TEX_CONST_4_BASE(uint32_t val)
+{
+       return ((val) << A4XX_TEX_CONST_4_BASE__SHIFT) & A4XX_TEX_CONST_4_BASE__MASK;
+}
+
+#define REG_A4XX_TEX_CONST_5                                   0x00000005
+
+#define REG_A4XX_TEX_CONST_6                                   0x00000006
+
+#define REG_A4XX_TEX_CONST_7                                   0x00000007
+
+
+#endif /* A4XX_XML */
diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c
new file mode 100644 (file)
index 0000000..9122183
--- /dev/null
@@ -0,0 +1,604 @@
+/* Copyright (c) 2014 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 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 "a4xx_gpu.h"
+#ifdef CONFIG_MSM_OCMEM
+#  include <soc/qcom/ocmem.h>
+#endif
+
+#define A4XX_INT0_MASK \
+       (A4XX_INT0_RBBM_AHB_ERROR |        \
+        A4XX_INT0_RBBM_ATB_BUS_OVERFLOW | \
+        A4XX_INT0_CP_T0_PACKET_IN_IB |    \
+        A4XX_INT0_CP_OPCODE_ERROR |       \
+        A4XX_INT0_CP_RESERVED_BIT_ERROR | \
+        A4XX_INT0_CP_HW_FAULT |           \
+        A4XX_INT0_CP_IB1_INT |            \
+        A4XX_INT0_CP_IB2_INT |            \
+        A4XX_INT0_CP_RB_INT |             \
+        A4XX_INT0_CP_REG_PROTECT_FAULT |  \
+        A4XX_INT0_CP_AHB_ERROR_HALT |     \
+        A4XX_INT0_UCHE_OOB_ACCESS)
+
+extern bool hang_debug;
+static void a4xx_dump(struct msm_gpu *gpu);
+
+/*
+ * a4xx_enable_hwcg() - Program the clock control registers
+ * @device: The adreno device pointer
+ */
+static void a4xx_enable_hwcg(struct msm_gpu *gpu)
+{
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       unsigned int i;
+       for (i = 0; i < 4; i++)
+               gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_TP(i), 0x02222202);
+       for (i = 0; i < 4; i++)
+               gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2_TP(i), 0x00002222);
+       for (i = 0; i < 4; i++)
+               gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_TP(i), 0x0E739CE7);
+       for (i = 0; i < 4; i++)
+               gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_TP(i), 0x00111111);
+       for (i = 0; i < 4; i++)
+               gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_SP(i), 0x22222222);
+       for (i = 0; i < 4; i++)
+               gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2_SP(i), 0x00222222);
+       for (i = 0; i < 4; i++)
+               gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_SP(i), 0x00000104);
+       for (i = 0; i < 4; i++)
+               gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_SP(i), 0x00000081);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_UCHE, 0x22222222);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2_UCHE, 0x02222222);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL3_UCHE, 0x00000000);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL4_UCHE, 0x00000000);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_UCHE, 0x00004444);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_UCHE, 0x00001112);
+       for (i = 0; i < 4; i++)
+               gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_RB(i), 0x22222222);
+
+       /* Disable L1 clocking in A420 due to CCU issues with it */
+       for (i = 0; i < 4; i++) {
+               if (adreno_is_a420(adreno_gpu)) {
+                       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2_RB(i),
+                                       0x00002020);
+               } else {
+                       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2_RB(i),
+                                       0x00022020);
+               }
+       }
+
+       for (i = 0; i < 4; i++) {
+               gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_MARB_CCU(i),
+                               0x00000922);
+       }
+
+       for (i = 0; i < 4; i++) {
+               gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_RB_MARB_CCU(i),
+                               0x00000000);
+       }
+
+       for (i = 0; i < 4; i++) {
+               gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_RB_MARB_CCU_L1(i),
+                               0x00000001);
+       }
+
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_MODE_GPC, 0x02222222);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_GPC, 0x04100104);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_GPC, 0x00022222);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_COM_DCOM, 0x00000022);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_COM_DCOM, 0x0000010F);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_COM_DCOM, 0x00000022);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_TSE_RAS_RBBM, 0x00222222);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_TSE_RAS_RBBM, 0x00004104);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_TSE_RAS_RBBM, 0x00000222);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_HLSQ , 0x00000000);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_HLSQ, 0x00000000);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_HLSQ, 0x00020000);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL, 0xAAAAAAAA);
+       gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2, 0);
+}
+
+static void a4xx_me_init(struct msm_gpu *gpu)
+{
+       struct msm_ringbuffer *ring = gpu->rb;
+
+       OUT_PKT3(ring, CP_ME_INIT, 17);
+       OUT_RING(ring, 0x000003f7);
+       OUT_RING(ring, 0x00000000);
+       OUT_RING(ring, 0x00000000);
+       OUT_RING(ring, 0x00000000);
+       OUT_RING(ring, 0x00000080);
+       OUT_RING(ring, 0x00000100);
+       OUT_RING(ring, 0x00000180);
+       OUT_RING(ring, 0x00006600);
+       OUT_RING(ring, 0x00000150);
+       OUT_RING(ring, 0x0000014e);
+       OUT_RING(ring, 0x00000154);
+       OUT_RING(ring, 0x00000001);
+       OUT_RING(ring, 0x00000000);
+       OUT_RING(ring, 0x00000000);
+       OUT_RING(ring, 0x00000000);
+       OUT_RING(ring, 0x00000000);
+       OUT_RING(ring, 0x00000000);
+
+       gpu->funcs->flush(gpu);
+       gpu->funcs->idle(gpu);
+}
+
+static int a4xx_hw_init(struct msm_gpu *gpu)
+{
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       struct a4xx_gpu *a4xx_gpu = to_a4xx_gpu(adreno_gpu);
+       uint32_t *ptr, len;
+       int i, ret;
+
+       if (adreno_is_a4xx(adreno_gpu)) {
+               gpu_write(gpu, REG_A4XX_VBIF_ABIT_SORT, 0x0001001F);
+               gpu_write(gpu, REG_A4XX_VBIF_ABIT_SORT_CONF, 0x000000A4);
+               gpu_write(gpu, REG_A4XX_VBIF_GATE_OFF_WRREQ_EN, 0x00000001);
+               gpu_write(gpu, REG_A4XX_VBIF_IN_RD_LIM_CONF0, 0x18181818);
+               gpu_write(gpu, REG_A4XX_VBIF_IN_RD_LIM_CONF1, 0x00000018);
+               gpu_write(gpu, REG_A4XX_VBIF_IN_WR_LIM_CONF0, 0x18181818);
+               gpu_write(gpu, REG_A4XX_VBIF_IN_WR_LIM_CONF1, 0x00000018);
+               gpu_write(gpu, REG_A4XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x00000003);
+       } else {
+               BUG();
+       }
+
+       /* Make all blocks contribute to the GPU BUSY perf counter */
+       gpu_write(gpu, REG_A4XX_RBBM_GPU_BUSY_MASKED, 0xffffffff);
+
+       /* Tune the hystersis counters for SP and CP idle detection */
+       gpu_write(gpu, REG_A4XX_RBBM_SP_HYST_CNT, 0x10);
+       gpu_write(gpu, REG_A4XX_RBBM_WAIT_IDLE_CLOCKS_CTL, 0x10);
+
+        /* Enable the RBBM error reporting bits */
+       gpu_write(gpu, REG_A4XX_RBBM_AHB_CTL0, 0x00000001);
+
+       /* Enable AHB error reporting*/
+       gpu_write(gpu, REG_A4XX_RBBM_AHB_CTL1, 0xa6ffffff);
+
+       /* Enable power counters*/
+       gpu_write(gpu, REG_A4XX_RBBM_RBBM_CTL, 0x00000030);
+
+       /*
+        * Turn on hang detection - this spews a lot of useful information
+        * into the RBBM registers on a hang:
+        */
+       gpu_write(gpu, REG_A4XX_RBBM_INTERFACE_HANG_INT_CTL,
+                       (1 << 30) | 0xFFFF);
+
+       gpu_write(gpu, REG_A4XX_RB_GMEM_BASE_ADDR,
+                       (unsigned int)(a4xx_gpu->ocmem_base >> 14));
+
+       /* Turn on performance counters: */
+       gpu_write(gpu, REG_A4XX_RBBM_PERFCTR_CTL, 0x01);
+
+       /* Disable L2 bypass to avoid UCHE out of bounds errors */
+       gpu_write(gpu, REG_A4XX_UCHE_TRAP_BASE_LO, 0xffff0000);
+       gpu_write(gpu, REG_A4XX_UCHE_TRAP_BASE_HI, 0xffff0000);
+
+       gpu_write(gpu, REG_A4XX_CP_DEBUG, (1 << 25) |
+                       (adreno_is_a420(adreno_gpu) ? (1 << 29) : 0));
+
+       a4xx_enable_hwcg(gpu);
+
+       /*
+        * For A420 set RBBM_CLOCK_DELAY_HLSQ.CGC_HLSQ_TP_EARLY_CYC >= 2
+        * due to timing issue with HLSQ_TP_CLK_EN
+        */
+       if (adreno_is_a420(adreno_gpu)) {
+               unsigned int val;
+               val = gpu_read(gpu, REG_A4XX_RBBM_CLOCK_DELAY_HLSQ);
+               val &= ~A4XX_CGC_HLSQ_EARLY_CYC__MASK;
+               val |= 2 << A4XX_CGC_HLSQ_EARLY_CYC__SHIFT;
+               gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_HLSQ, val);
+       }
+
+       ret = adreno_hw_init(gpu);
+       if (ret)
+               return ret;
+
+       /* setup access protection: */
+       gpu_write(gpu, REG_A4XX_CP_PROTECT_CTRL, 0x00000007);
+
+       /* RBBM registers */
+       gpu_write(gpu, REG_A4XX_CP_PROTECT(0), 0x62000010);
+       gpu_write(gpu, REG_A4XX_CP_PROTECT(1), 0x63000020);
+       gpu_write(gpu, REG_A4XX_CP_PROTECT(2), 0x64000040);
+       gpu_write(gpu, REG_A4XX_CP_PROTECT(3), 0x65000080);
+       gpu_write(gpu, REG_A4XX_CP_PROTECT(4), 0x66000100);
+       gpu_write(gpu, REG_A4XX_CP_PROTECT(5), 0x64000200);
+
+       /* CP registers */
+       gpu_write(gpu, REG_A4XX_CP_PROTECT(6), 0x67000800);
+       gpu_write(gpu, REG_A4XX_CP_PROTECT(7), 0x64001600);
+
+
+       /* RB registers */
+       gpu_write(gpu, REG_A4XX_CP_PROTECT(8), 0x60003300);
+
+       /* HLSQ registers */
+       gpu_write(gpu, REG_A4XX_CP_PROTECT(9), 0x60003800);
+
+       /* VPC registers */
+       gpu_write(gpu, REG_A4XX_CP_PROTECT(10), 0x61003980);
+
+       /* SMMU registers */
+       gpu_write(gpu, REG_A4XX_CP_PROTECT(11), 0x6e010000);
+
+       gpu_write(gpu, REG_A4XX_RBBM_INT_0_MASK, A4XX_INT0_MASK);
+
+       ret = adreno_hw_init(gpu);
+       if (ret)
+               return ret;
+
+       /* Load PM4: */
+       ptr = (uint32_t *)(adreno_gpu->pm4->data);
+       len = adreno_gpu->pm4->size / 4;
+       DBG("loading PM4 ucode version: %u", ptr[0]);
+       gpu_write(gpu, REG_A4XX_CP_ME_RAM_WADDR, 0);
+       for (i = 1; i < len; i++)
+               gpu_write(gpu, REG_A4XX_CP_ME_RAM_DATA, ptr[i]);
+
+       /* Load PFP: */
+       ptr = (uint32_t *)(adreno_gpu->pfp->data);
+       len = adreno_gpu->pfp->size / 4;
+       DBG("loading PFP ucode version: %u", ptr[0]);
+
+       gpu_write(gpu, REG_A4XX_CP_PFP_UCODE_ADDR, 0);
+       for (i = 1; i < len; i++)
+               gpu_write(gpu, REG_A4XX_CP_PFP_UCODE_DATA, ptr[i]);
+
+       /* clear ME_HALT to start micro engine */
+       gpu_write(gpu, REG_A4XX_CP_ME_CNTL, 0);
+
+       a4xx_me_init(gpu);
+       return 0;
+}
+
+static void a4xx_recover(struct msm_gpu *gpu)
+{
+       /* dump registers before resetting gpu, if enabled: */
+       if (hang_debug)
+               a4xx_dump(gpu);
+
+       gpu_write(gpu, REG_A4XX_RBBM_SW_RESET_CMD, 1);
+       gpu_read(gpu, REG_A4XX_RBBM_SW_RESET_CMD);
+       gpu_write(gpu, REG_A4XX_RBBM_SW_RESET_CMD, 0);
+       adreno_recover(gpu);
+}
+
+static void a4xx_destroy(struct msm_gpu *gpu)
+{
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       struct a4xx_gpu *a4xx_gpu = to_a4xx_gpu(adreno_gpu);
+
+       DBG("%s", gpu->name);
+
+       adreno_gpu_cleanup(adreno_gpu);
+
+#ifdef CONFIG_MSM_OCMEM
+       if (a4xx_gpu->ocmem_base)
+               ocmem_free(OCMEM_GRAPHICS, a4xx_gpu->ocmem_hdl);
+#endif
+
+       kfree(a4xx_gpu);
+}
+
+static void a4xx_idle(struct msm_gpu *gpu)
+{
+       /* wait for ringbuffer to drain: */
+       adreno_idle(gpu);
+
+       /* then wait for GPU to finish: */
+       if (spin_until(!(gpu_read(gpu, REG_A4XX_RBBM_STATUS) &
+                                       A4XX_RBBM_STATUS_GPU_BUSY)))
+               DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name);
+
+       /* TODO maybe we need to reset GPU here to recover from hang? */
+}
+
+static irqreturn_t a4xx_irq(struct msm_gpu *gpu)
+{
+       uint32_t status;
+
+       status = gpu_read(gpu, REG_A4XX_RBBM_INT_0_STATUS);
+       DBG("%s: Int status %08x", gpu->name, status);
+
+       gpu_write(gpu, REG_A4XX_RBBM_INT_CLEAR_CMD, status);
+
+       msm_gpu_retire(gpu);
+
+       return IRQ_HANDLED;
+}
+
+static const unsigned int a4xx_registers[] = {
+       /* RBBM */
+       0x0000, 0x0002, 0x0004, 0x0021, 0x0023, 0x0024, 0x0026, 0x0026,
+       0x0028, 0x002B, 0x002E, 0x0034, 0x0037, 0x0044, 0x0047, 0x0066,
+       0x0068, 0x0095, 0x009C, 0x0170, 0x0174, 0x01AF,
+       /* CP */
+       0x0200, 0x0233, 0x0240, 0x0250, 0x04C0, 0x04DD, 0x0500, 0x050B,
+       0x0578, 0x058F,
+       /* VSC */
+       0x0C00, 0x0C03, 0x0C08, 0x0C41, 0x0C50, 0x0C51,
+       /* GRAS */
+       0x0C80, 0x0C81, 0x0C88, 0x0C8F,
+       /* RB */
+       0x0CC0, 0x0CC0, 0x0CC4, 0x0CD2,
+       /* PC */
+       0x0D00, 0x0D0C, 0x0D10, 0x0D17, 0x0D20, 0x0D23,
+       /* VFD */
+       0x0E40, 0x0E4A,
+       /* VPC */
+       0x0E60, 0x0E61, 0x0E63, 0x0E68,
+       /* UCHE */
+       0x0E80, 0x0E84, 0x0E88, 0x0E95,
+       /* VMIDMT */
+       0x1000, 0x1000, 0x1002, 0x1002, 0x1004, 0x1004, 0x1008, 0x100A,
+       0x100C, 0x100D, 0x100F, 0x1010, 0x1012, 0x1016, 0x1024, 0x1024,
+       0x1027, 0x1027, 0x1100, 0x1100, 0x1102, 0x1102, 0x1104, 0x1104,
+       0x1110, 0x1110, 0x1112, 0x1116, 0x1124, 0x1124, 0x1300, 0x1300,
+       0x1380, 0x1380,
+       /* GRAS CTX 0 */
+       0x2000, 0x2004, 0x2008, 0x2067, 0x2070, 0x2078, 0x207B, 0x216E,
+       /* PC CTX 0 */
+       0x21C0, 0x21C6, 0x21D0, 0x21D0, 0x21D9, 0x21D9, 0x21E5, 0x21E7,
+       /* VFD CTX 0 */
+       0x2200, 0x2204, 0x2208, 0x22A9,
+       /* GRAS CTX 1 */
+       0x2400, 0x2404, 0x2408, 0x2467, 0x2470, 0x2478, 0x247B, 0x256E,
+       /* PC CTX 1 */
+       0x25C0, 0x25C6, 0x25D0, 0x25D0, 0x25D9, 0x25D9, 0x25E5, 0x25E7,
+       /* VFD CTX 1 */
+       0x2600, 0x2604, 0x2608, 0x26A9,
+       /* XPU */
+       0x2C00, 0x2C01, 0x2C10, 0x2C10, 0x2C12, 0x2C16, 0x2C1D, 0x2C20,
+       0x2C28, 0x2C28, 0x2C30, 0x2C30, 0x2C32, 0x2C36, 0x2C40, 0x2C40,
+       0x2C50, 0x2C50, 0x2C52, 0x2C56, 0x2C80, 0x2C80, 0x2C94, 0x2C95,
+       /* VBIF */
+       0x3000, 0x3007, 0x300C, 0x3014, 0x3018, 0x301D, 0x3020, 0x3022,
+       0x3024, 0x3026, 0x3028, 0x302A, 0x302C, 0x302D, 0x3030, 0x3031,
+       0x3034, 0x3036, 0x3038, 0x3038, 0x303C, 0x303D, 0x3040, 0x3040,
+       0x3049, 0x3049, 0x3058, 0x3058, 0x305B, 0x3061, 0x3064, 0x3068,
+       0x306C, 0x306D, 0x3080, 0x3088, 0x308B, 0x308C, 0x3090, 0x3094,
+       0x3098, 0x3098, 0x309C, 0x309C, 0x30C0, 0x30C0, 0x30C8, 0x30C8,
+       0x30D0, 0x30D0, 0x30D8, 0x30D8, 0x30E0, 0x30E0, 0x3100, 0x3100,
+       0x3108, 0x3108, 0x3110, 0x3110, 0x3118, 0x3118, 0x3120, 0x3120,
+       0x3124, 0x3125, 0x3129, 0x3129, 0x3131, 0x3131, 0x330C, 0x330C,
+       0x3310, 0x3310, 0x3400, 0x3401, 0x3410, 0x3410, 0x3412, 0x3416,
+       0x341D, 0x3420, 0x3428, 0x3428, 0x3430, 0x3430, 0x3432, 0x3436,
+       0x3440, 0x3440, 0x3450, 0x3450, 0x3452, 0x3456, 0x3480, 0x3480,
+       0x3494, 0x3495, 0x4000, 0x4000, 0x4002, 0x4002, 0x4004, 0x4004,
+       0x4008, 0x400A, 0x400C, 0x400D, 0x400F, 0x4012, 0x4014, 0x4016,
+       0x401D, 0x401D, 0x4020, 0x4027, 0x4060, 0x4062, 0x4200, 0x4200,
+       0x4300, 0x4300, 0x4400, 0x4400, 0x4500, 0x4500, 0x4800, 0x4802,
+       0x480F, 0x480F, 0x4811, 0x4811, 0x4813, 0x4813, 0x4815, 0x4816,
+       0x482B, 0x482B, 0x4857, 0x4857, 0x4883, 0x4883, 0x48AF, 0x48AF,
+       0x48C5, 0x48C5, 0x48E5, 0x48E5, 0x4905, 0x4905, 0x4925, 0x4925,
+       0x4945, 0x4945, 0x4950, 0x4950, 0x495B, 0x495B, 0x4980, 0x498E,
+       0x4B00, 0x4B00, 0x4C00, 0x4C00, 0x4D00, 0x4D00, 0x4E00, 0x4E00,
+       0x4E80, 0x4E80, 0x4F00, 0x4F00, 0x4F08, 0x4F08, 0x4F10, 0x4F10,
+       0x4F18, 0x4F18, 0x4F20, 0x4F20, 0x4F30, 0x4F30, 0x4F60, 0x4F60,
+       0x4F80, 0x4F81, 0x4F88, 0x4F89, 0x4FEE, 0x4FEE, 0x4FF3, 0x4FF3,
+       0x6000, 0x6001, 0x6008, 0x600F, 0x6014, 0x6016, 0x6018, 0x601B,
+       0x61FD, 0x61FD, 0x623C, 0x623C, 0x6380, 0x6380, 0x63A0, 0x63A0,
+       0x63C0, 0x63C1, 0x63C8, 0x63C9, 0x63D0, 0x63D4, 0x63D6, 0x63D6,
+       0x63EE, 0x63EE, 0x6400, 0x6401, 0x6408, 0x640F, 0x6414, 0x6416,
+       0x6418, 0x641B, 0x65FD, 0x65FD, 0x663C, 0x663C, 0x6780, 0x6780,
+       0x67A0, 0x67A0, 0x67C0, 0x67C1, 0x67C8, 0x67C9, 0x67D0, 0x67D4,
+       0x67D6, 0x67D6, 0x67EE, 0x67EE, 0x6800, 0x6801, 0x6808, 0x680F,
+       0x6814, 0x6816, 0x6818, 0x681B, 0x69FD, 0x69FD, 0x6A3C, 0x6A3C,
+       0x6B80, 0x6B80, 0x6BA0, 0x6BA0, 0x6BC0, 0x6BC1, 0x6BC8, 0x6BC9,
+       0x6BD0, 0x6BD4, 0x6BD6, 0x6BD6, 0x6BEE, 0x6BEE,
+       ~0 /* sentinel */
+};
+
+#ifdef CONFIG_DEBUG_FS
+static void a4xx_show(struct msm_gpu *gpu, struct seq_file *m)
+{
+       gpu->funcs->pm_resume(gpu);
+
+       seq_printf(m, "status:   %08x\n",
+                       gpu_read(gpu, REG_A4XX_RBBM_STATUS));
+       gpu->funcs->pm_suspend(gpu);
+
+       adreno_show(gpu, m);
+
+}
+#endif
+
+/* Register offset defines for A4XX, in order of enum adreno_regs */
+static const unsigned int a4xx_register_offsets[REG_ADRENO_REGISTER_MAX] = {
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_DEBUG, REG_A4XX_CP_DEBUG),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_ME_RAM_WADDR, REG_A4XX_CP_ME_RAM_WADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_ME_RAM_DATA, REG_A4XX_CP_ME_RAM_DATA),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_PFP_UCODE_DATA,
+                       REG_A4XX_CP_PFP_UCODE_DATA),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_PFP_UCODE_ADDR,
+                       REG_A4XX_CP_PFP_UCODE_ADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_WFI_PEND_CTR, REG_A4XX_CP_WFI_PEND_CTR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE, REG_A4XX_CP_RB_BASE),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR_ADDR, REG_A4XX_CP_RB_RPTR_ADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_RPTR, REG_A4XX_CP_RB_RPTR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_WPTR, REG_A4XX_CP_RB_WPTR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_PROTECT_CTRL, REG_A4XX_CP_PROTECT_CTRL),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_ME_CNTL, REG_A4XX_CP_ME_CNTL),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_CNTL, REG_A4XX_CP_RB_CNTL),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_IB1_BASE, REG_A4XX_CP_IB1_BASE),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_IB1_BUFSZ, REG_A4XX_CP_IB1_BUFSZ),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_IB2_BASE, REG_A4XX_CP_IB2_BASE),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_IB2_BUFSZ, REG_A4XX_CP_IB2_BUFSZ),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_TIMESTAMP, REG_AXXX_CP_SCRATCH_REG0),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_ME_RAM_RADDR, REG_A4XX_CP_ME_RAM_RADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_ROQ_ADDR, REG_A4XX_CP_ROQ_ADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_ROQ_DATA, REG_A4XX_CP_ROQ_DATA),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_MERCIU_ADDR, REG_A4XX_CP_MERCIU_ADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_MERCIU_DATA, REG_A4XX_CP_MERCIU_DATA),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_MERCIU_DATA2, REG_A4XX_CP_MERCIU_DATA2),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_MEQ_ADDR, REG_A4XX_CP_MEQ_ADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_MEQ_DATA, REG_A4XX_CP_MEQ_DATA),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_HW_FAULT, REG_A4XX_CP_HW_FAULT),
+       REG_ADRENO_DEFINE(REG_ADRENO_CP_PROTECT_STATUS,
+                       REG_A4XX_CP_PROTECT_STATUS),
+       REG_ADRENO_DEFINE(REG_ADRENO_SCRATCH_ADDR, REG_A4XX_CP_SCRATCH_ADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_SCRATCH_UMSK, REG_A4XX_CP_SCRATCH_UMASK),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_STATUS, REG_A4XX_RBBM_STATUS),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_CTL,
+                       REG_A4XX_RBBM_PERFCTR_CTL),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_CMD0,
+                       REG_A4XX_RBBM_PERFCTR_LOAD_CMD0),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_CMD1,
+                       REG_A4XX_RBBM_PERFCTR_LOAD_CMD1),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_CMD2,
+                       REG_A4XX_RBBM_PERFCTR_LOAD_CMD2),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_PWR_1_LO,
+                       REG_A4XX_RBBM_PERFCTR_PWR_1_LO),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_INT_0_MASK, REG_A4XX_RBBM_INT_0_MASK),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_INT_0_STATUS,
+                       REG_A4XX_RBBM_INT_0_STATUS),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_AHB_ERROR_STATUS,
+                       REG_A4XX_RBBM_AHB_ERROR_STATUS),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_AHB_CMD, REG_A4XX_RBBM_AHB_CMD),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_CLOCK_CTL, REG_A4XX_RBBM_CLOCK_CTL),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_AHB_ME_SPLIT_STATUS,
+                       REG_A4XX_RBBM_AHB_ME_SPLIT_STATUS),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_AHB_PFP_SPLIT_STATUS,
+                       REG_A4XX_RBBM_AHB_PFP_SPLIT_STATUS),
+       REG_ADRENO_DEFINE(REG_ADRENO_VPC_DEBUG_RAM_SEL,
+                       REG_A4XX_VPC_DEBUG_RAM_SEL),
+       REG_ADRENO_DEFINE(REG_ADRENO_VPC_DEBUG_RAM_READ,
+                       REG_A4XX_VPC_DEBUG_RAM_READ),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_INT_CLEAR_CMD,
+                       REG_A4XX_RBBM_INT_CLEAR_CMD),
+       REG_ADRENO_DEFINE(REG_ADRENO_VSC_SIZE_ADDRESS,
+                       REG_A4XX_VSC_SIZE_ADDRESS),
+       REG_ADRENO_DEFINE(REG_ADRENO_VFD_CONTROL_0, REG_A4XX_VFD_CONTROL_0),
+       REG_ADRENO_DEFINE(REG_ADRENO_SP_VS_PVT_MEM_ADDR_REG,
+                       REG_A4XX_SP_VS_PVT_MEM_ADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_SP_FS_PVT_MEM_ADDR_REG,
+                       REG_A4XX_SP_FS_PVT_MEM_ADDR),
+       REG_ADRENO_DEFINE(REG_ADRENO_SP_VS_OBJ_START_REG,
+                       REG_A4XX_SP_VS_OBJ_START),
+       REG_ADRENO_DEFINE(REG_ADRENO_SP_FS_OBJ_START_REG,
+                       REG_A4XX_SP_FS_OBJ_START),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_RBBM_CTL, REG_A4XX_RBBM_RBBM_CTL),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_SW_RESET_CMD,
+                       REG_A4XX_RBBM_SW_RESET_CMD),
+       REG_ADRENO_DEFINE(REG_ADRENO_UCHE_INVALIDATE0,
+                       REG_A4XX_UCHE_INVALIDATE0),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_VALUE_LO,
+                       REG_A4XX_RBBM_PERFCTR_LOAD_VALUE_LO),
+       REG_ADRENO_DEFINE(REG_ADRENO_RBBM_PERFCTR_LOAD_VALUE_HI,
+                       REG_A4XX_RBBM_PERFCTR_LOAD_VALUE_HI),
+};
+
+static void a4xx_dump(struct msm_gpu *gpu)
+{
+       adreno_dump(gpu);
+       printk("status:   %08x\n",
+                       gpu_read(gpu, REG_A4XX_RBBM_STATUS));
+       adreno_dump(gpu);
+}
+
+static const struct adreno_gpu_funcs funcs = {
+       .base = {
+               .get_param = adreno_get_param,
+               .hw_init = a4xx_hw_init,
+               .pm_suspend = msm_gpu_pm_suspend,
+               .pm_resume = msm_gpu_pm_resume,
+               .recover = a4xx_recover,
+               .last_fence = adreno_last_fence,
+               .submit = adreno_submit,
+               .flush = adreno_flush,
+               .idle = a4xx_idle,
+               .irq = a4xx_irq,
+               .destroy = a4xx_destroy,
+#ifdef CONFIG_DEBUG_FS
+               .show = a4xx_show,
+#endif
+       },
+};
+
+struct msm_gpu *a4xx_gpu_init(struct drm_device *dev)
+{
+       struct a4xx_gpu *a4xx_gpu = NULL;
+       struct adreno_gpu *adreno_gpu;
+       struct msm_gpu *gpu;
+       struct msm_drm_private *priv = dev->dev_private;
+       struct platform_device *pdev = priv->gpu_pdev;
+       int ret;
+
+       if (!pdev) {
+               dev_err(dev->dev, "no a4xx device\n");
+               ret = -ENXIO;
+               goto fail;
+       }
+
+       a4xx_gpu = kzalloc(sizeof(*a4xx_gpu), GFP_KERNEL);
+       if (!a4xx_gpu) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       adreno_gpu = &a4xx_gpu->base;
+       gpu = &adreno_gpu->base;
+
+       a4xx_gpu->pdev = pdev;
+
+       gpu->perfcntrs = NULL;
+       gpu->num_perfcntrs = 0;
+
+       adreno_gpu->registers = a4xx_registers;
+       adreno_gpu->reg_offsets = a4xx_register_offsets;
+
+       ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs);
+       if (ret)
+               goto fail;
+
+       /* if needed, allocate gmem: */
+       if (adreno_is_a4xx(adreno_gpu)) {
+#ifdef CONFIG_MSM_OCMEM
+               /* TODO this is different/missing upstream: */
+               struct ocmem_buf *ocmem_hdl =
+                               ocmem_allocate(OCMEM_GRAPHICS, adreno_gpu->gmem);
+
+               a4xx_gpu->ocmem_hdl = ocmem_hdl;
+               a4xx_gpu->ocmem_base = ocmem_hdl->addr;
+               adreno_gpu->gmem = ocmem_hdl->len;
+               DBG("using %dK of OCMEM at 0x%08x", adreno_gpu->gmem / 1024,
+                               a4xx_gpu->ocmem_base);
+#endif
+       }
+
+       if (!gpu->mmu) {
+               /* TODO we think it is possible to configure the GPU to
+                * restrict access to VRAM carveout.  But the required
+                * registers are unknown.  For now just bail out and
+                * limp along with just modesetting.  If it turns out
+                * to not be possible to restrict access, then we must
+                * implement a cmdstream validator.
+                */
+               dev_err(dev->dev, "No memory protection without IOMMU\n");
+               ret = -ENXIO;
+               goto fail;
+       }
+
+       return gpu;
+
+fail:
+       if (a4xx_gpu)
+               a4xx_destroy(&a4xx_gpu->base.base);
+
+       return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.h b/drivers/gpu/drm/msm/adreno/a4xx_gpu.h
new file mode 100644 (file)
index 0000000..0124720
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (c) 2014 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 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.
+ *
+ */
+#ifndef __A4XX_GPU_H__
+#define __A4XX_GPU_H__
+
+#include "adreno_gpu.h"
+
+/* arrg, somehow fb.h is getting pulled in: */
+#undef ROP_COPY
+#undef ROP_XOR
+
+#include "a4xx.xml.h"
+
+struct a4xx_gpu {
+       struct adreno_gpu base;
+       struct platform_device *pdev;
+
+       /* if OCMEM is used for GMEM: */
+       uint32_t ocmem_base;
+       void *ocmem_hdl;
+};
+#define to_a4xx_gpu(x) container_of(x, struct a4xx_gpu, base)
+
+#endif /* __A4XX_GPU_H__ */
index cc341bc62b51f8ff860f85e11663c6d6d2f2ff81..a4b33af9338daedd4ebd7345987326c416188be4 100644 (file)
@@ -11,10 +11,10 @@ The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (   9859 bytes, from 2014-06-02 15:21:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14960 bytes, from 2014-07-27 17:22:13)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  58020 bytes, from 2014-08-01 12:22:48)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  41068 bytes, from 2014-08-01 12:22:48)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2014-11-13 22:44:30)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  15053 bytes, from 2014-11-09 15:45:47)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  63169 bytes, from 2014-11-13 22:44:18)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  49097 bytes, from 2014-11-14 15:38:00)
 
 Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -105,6 +105,7 @@ enum adreno_rb_dither_mode {
 enum adreno_rb_depth_format {
        DEPTHX_16 = 0,
        DEPTHX_24_8 = 1,
+       DEPTHX_32 = 2,
 };
 
 enum adreno_rb_copy_control_mode {
@@ -132,6 +133,7 @@ enum a3xx_threadmode {
 };
 
 enum a3xx_instrbuffermode {
+       CACHE = 0,
        BUFFER = 1,
 };
 
@@ -140,6 +142,13 @@ enum a3xx_threadsize {
        FOUR_QUADS = 1,
 };
 
+enum a3xx_color_swap {
+       WZYX = 0,
+       WXYZ = 1,
+       ZYXW = 2,
+       XYZW = 3,
+};
+
 #define REG_AXXX_CP_RB_BASE                                    0x000001c0
 
 #define REG_AXXX_CP_RB_CNTL                                    0x000001c1
index 7ab85af3a7dbcc8b83299229bbbeac39ca99e05f..be83dee83d08246cdf29922caa74b6fab75584ce 100644 (file)
@@ -2,6 +2,8 @@
  * Copyright (C) 2013-2014 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
+ * Copyright (c) 2014 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.
@@ -28,6 +30,7 @@ MODULE_PARM_DESC(hang_debug, "Dump registers when hang is detected (can be slow!
 module_param_named(hang_debug, hang_debug, bool, 0600);
 
 struct msm_gpu *a3xx_gpu_init(struct drm_device *dev);
+struct msm_gpu *a4xx_gpu_init(struct drm_device *dev);
 
 static const struct adreno_info gpulist[] = {
        {
@@ -54,6 +57,14 @@ static const struct adreno_info gpulist[] = {
                .pfpfw = "a330_pfp.fw",
                .gmem  = SZ_1M,
                .init  = a3xx_gpu_init,
+       }, {
+               .rev   = ADRENO_REV(4, 2, 0, ANY_ID),
+               .revn  = 420,
+               .name  = "A420",
+               .pm4fw = "a420_pm4.fw",
+               .pfpfw = "a420_pfp.fw",
+               .gmem  = (SZ_1M + SZ_512K),
+               .init  = a4xx_gpu_init,
        },
 };
 
@@ -61,6 +72,8 @@ MODULE_FIRMWARE("a300_pm4.fw");
 MODULE_FIRMWARE("a300_pfp.fw");
 MODULE_FIRMWARE("a330_pm4.fw");
 MODULE_FIRMWARE("a330_pfp.fw");
+MODULE_FIRMWARE("a420_pm4.fw");
+MODULE_FIRMWARE("a420_pfp.fw");
 
 static inline bool _rev_match(uint8_t entry, uint8_t id)
 {
index 6afa29167fee74fffaae26e8d7ded15d05ec87eb..aa873048308b8e6e3e431152963aed5b04c13f02 100644 (file)
@@ -2,6 +2,8 @@
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
+ * Copyright (c) 2014 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.
@@ -63,19 +65,21 @@ int adreno_hw_init(struct msm_gpu *gpu)
        }
 
        /* Setup REG_CP_RB_CNTL: */
-       gpu_write(gpu, REG_AXXX_CP_RB_CNTL,
+       adreno_gpu_write(adreno_gpu, REG_ADRENO_CP_RB_CNTL,
                        /* size is log2(quad-words): */
                        AXXX_CP_RB_CNTL_BUFSZ(ilog2(gpu->rb->size / 8)) |
                        AXXX_CP_RB_CNTL_BLKSZ(ilog2(RB_BLKSIZE / 8)));
 
        /* Setup ringbuffer address: */
-       gpu_write(gpu, REG_AXXX_CP_RB_BASE, gpu->rb_iova);
-       gpu_write(gpu, REG_AXXX_CP_RB_RPTR_ADDR, rbmemptr(adreno_gpu, rptr));
+       adreno_gpu_write(adreno_gpu, REG_ADRENO_CP_RB_BASE, gpu->rb_iova);
+       adreno_gpu_write(adreno_gpu, REG_ADRENO_CP_RB_RPTR_ADDR,
+                       rbmemptr(adreno_gpu, rptr));
 
        /* Setup scratch/timestamp: */
-       gpu_write(gpu, REG_AXXX_SCRATCH_ADDR, rbmemptr(adreno_gpu, fence));
+       adreno_gpu_write(adreno_gpu, REG_ADRENO_SCRATCH_ADDR,
+                       rbmemptr(adreno_gpu, fence));
 
-       gpu_write(gpu, REG_AXXX_SCRATCH_UMSK, 0x1);
+       adreno_gpu_write(adreno_gpu, REG_ADRENO_SCRATCH_UMSK, 0x1);
 
        return 0;
 }
@@ -151,7 +155,7 @@ int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
        OUT_PKT0(ring, REG_AXXX_CP_SCRATCH_REG2, 1);
        OUT_RING(ring, submit->fence);
 
-       if (adreno_is_a3xx(adreno_gpu)) {
+       if (adreno_is_a3xx(adreno_gpu) || adreno_is_a4xx(adreno_gpu)) {
                /* Flush HLSQ lazy updates to make sure there is nothing
                 * pending for indirect loads after the timestamp has
                 * passed:
@@ -188,12 +192,13 @@ int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
 
 void adreno_flush(struct msm_gpu *gpu)
 {
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
        uint32_t wptr = get_wptr(gpu->rb);
 
        /* ensure writes to ringbuffer have hit system memory: */
        mb();
 
-       gpu_write(gpu, REG_AXXX_CP_RB_WPTR, wptr);
+       adreno_gpu_write(adreno_gpu, REG_ADRENO_CP_RB_WPTR, wptr);
 }
 
 void adreno_idle(struct msm_gpu *gpu)
@@ -319,6 +324,12 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
        DBG("fast_rate=%u, slow_rate=%u, bus_freq=%u",
                        gpu->fast_rate, gpu->slow_rate, gpu->bus_freq);
 
+       ret = msm_gpu_init(drm, pdev, &adreno_gpu->base, &funcs->base,
+                       adreno_gpu->info->name, "kgsl_3d0_reg_memory", "kgsl_3d0_irq",
+                       RB_SIZE);
+       if (ret)
+               return ret;
+
        ret = request_firmware(&adreno_gpu->pm4, adreno_gpu->info->pm4fw, drm->dev);
        if (ret) {
                dev_err(drm->dev, "failed to load %s PM4 firmware: %d\n",
@@ -333,12 +344,6 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
                return ret;
        }
 
-       ret = msm_gpu_init(drm, pdev, &adreno_gpu->base, &funcs->base,
-                       adreno_gpu->info->name, "kgsl_3d0_reg_memory", "kgsl_3d0_irq",
-                       RB_SIZE);
-       if (ret)
-               return ret;
-
        mmu = gpu->mmu;
        if (mmu) {
                ret = mmu->funcs->attach(mmu, iommu_ports,
index 52f0515797532cef0d4496918fe421306946d0a5..a0cc30977e671d7286d52bba94cb3d09192c55d6 100644 (file)
@@ -2,6 +2,8 @@
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
+ * Copyright (c) 2014 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.
 #include "adreno_common.xml.h"
 #include "adreno_pm4.xml.h"
 
+#define REG_ADRENO_DEFINE(_offset, _reg) [_offset] = (_reg) + 1
+/**
+ * adreno_regs: List of registers that are used in across all
+ * 3D devices. Each device type has different offset value for the same
+ * register, so an array of register offsets are declared for every device
+ * and are indexed by the enumeration values defined in this enum
+ */
+enum adreno_regs {
+       REG_ADRENO_CP_DEBUG,
+       REG_ADRENO_CP_ME_RAM_WADDR,
+       REG_ADRENO_CP_ME_RAM_DATA,
+       REG_ADRENO_CP_PFP_UCODE_DATA,
+       REG_ADRENO_CP_PFP_UCODE_ADDR,
+       REG_ADRENO_CP_WFI_PEND_CTR,
+       REG_ADRENO_CP_RB_BASE,
+       REG_ADRENO_CP_RB_RPTR_ADDR,
+       REG_ADRENO_CP_RB_RPTR,
+       REG_ADRENO_CP_RB_WPTR,
+       REG_ADRENO_CP_PROTECT_CTRL,
+       REG_ADRENO_CP_ME_CNTL,
+       REG_ADRENO_CP_RB_CNTL,
+       REG_ADRENO_CP_IB1_BASE,
+       REG_ADRENO_CP_IB1_BUFSZ,
+       REG_ADRENO_CP_IB2_BASE,
+       REG_ADRENO_CP_IB2_BUFSZ,
+       REG_ADRENO_CP_TIMESTAMP,
+       REG_ADRENO_CP_ME_RAM_RADDR,
+       REG_ADRENO_CP_ROQ_ADDR,
+       REG_ADRENO_CP_ROQ_DATA,
+       REG_ADRENO_CP_MERCIU_ADDR,
+       REG_ADRENO_CP_MERCIU_DATA,
+       REG_ADRENO_CP_MERCIU_DATA2,
+       REG_ADRENO_CP_MEQ_ADDR,
+       REG_ADRENO_CP_MEQ_DATA,
+       REG_ADRENO_CP_HW_FAULT,
+       REG_ADRENO_CP_PROTECT_STATUS,
+       REG_ADRENO_SCRATCH_ADDR,
+       REG_ADRENO_SCRATCH_UMSK,
+       REG_ADRENO_SCRATCH_REG2,
+       REG_ADRENO_RBBM_STATUS,
+       REG_ADRENO_RBBM_PERFCTR_CTL,
+       REG_ADRENO_RBBM_PERFCTR_LOAD_CMD0,
+       REG_ADRENO_RBBM_PERFCTR_LOAD_CMD1,
+       REG_ADRENO_RBBM_PERFCTR_LOAD_CMD2,
+       REG_ADRENO_RBBM_PERFCTR_PWR_1_LO,
+       REG_ADRENO_RBBM_INT_0_MASK,
+       REG_ADRENO_RBBM_INT_0_STATUS,
+       REG_ADRENO_RBBM_AHB_ERROR_STATUS,
+       REG_ADRENO_RBBM_PM_OVERRIDE2,
+       REG_ADRENO_RBBM_AHB_CMD,
+       REG_ADRENO_RBBM_INT_CLEAR_CMD,
+       REG_ADRENO_RBBM_SW_RESET_CMD,
+       REG_ADRENO_RBBM_CLOCK_CTL,
+       REG_ADRENO_RBBM_AHB_ME_SPLIT_STATUS,
+       REG_ADRENO_RBBM_AHB_PFP_SPLIT_STATUS,
+       REG_ADRENO_VPC_DEBUG_RAM_SEL,
+       REG_ADRENO_VPC_DEBUG_RAM_READ,
+       REG_ADRENO_VSC_SIZE_ADDRESS,
+       REG_ADRENO_VFD_CONTROL_0,
+       REG_ADRENO_VFD_INDEX_MAX,
+       REG_ADRENO_SP_VS_PVT_MEM_ADDR_REG,
+       REG_ADRENO_SP_FS_PVT_MEM_ADDR_REG,
+       REG_ADRENO_SP_VS_OBJ_START_REG,
+       REG_ADRENO_SP_FS_OBJ_START_REG,
+       REG_ADRENO_PA_SC_AA_CONFIG,
+       REG_ADRENO_SQ_GPR_MANAGEMENT,
+       REG_ADRENO_SQ_INST_STORE_MANAGMENT,
+       REG_ADRENO_TP0_CHICKEN,
+       REG_ADRENO_RBBM_RBBM_CTL,
+       REG_ADRENO_UCHE_INVALIDATE0,
+       REG_ADRENO_RBBM_PERFCTR_LOAD_VALUE_LO,
+       REG_ADRENO_RBBM_PERFCTR_LOAD_VALUE_HI,
+       REG_ADRENO_REGISTER_MAX,
+};
+
 struct adreno_rev {
        uint8_t  core;
        uint8_t  major;
@@ -76,6 +153,13 @@ struct adreno_gpu {
        struct adreno_rbmemptrs *memptrs;
        struct drm_gem_object *memptrs_bo;
        uint32_t memptrs_iova;
+
+       /*
+        * Register offsets are different between some GPUs.
+        * GPU specific offsets will be exported by GPU specific
+        * code (a3xx_gpu.c) and stored in this common location.
+        */
+       const unsigned int *reg_offsets;
 };
 #define to_adreno_gpu(x) container_of(x, struct adreno_gpu, base)
 
@@ -128,6 +212,16 @@ static inline bool adreno_is_a330v2(struct adreno_gpu *gpu)
        return adreno_is_a330(gpu) && (gpu->rev.patchid > 0);
 }
 
+static inline bool adreno_is_a4xx(struct adreno_gpu *gpu)
+{
+       return (gpu->revn >= 400) && (gpu->revn < 500);
+}
+
+static inline int adreno_is_a420(struct adreno_gpu *gpu)
+{
+       return gpu->revn == 420;
+}
+
 int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value);
 int adreno_hw_init(struct msm_gpu *gpu);
 uint32_t adreno_last_fence(struct msm_gpu *gpu);
@@ -171,5 +265,37 @@ OUT_PKT3(struct msm_ringbuffer *ring, uint8_t opcode, uint16_t cnt)
        OUT_RING(ring, CP_TYPE3_PKT | ((cnt-1) << 16) | ((opcode & 0xFF) << 8));
 }
 
+/*
+ * adreno_checkreg_off() - Checks the validity of a register enum
+ * @gpu:               Pointer to struct adreno_gpu
+ * @offset_name:       The register enum that is checked
+ */
+static inline bool adreno_reg_check(struct adreno_gpu *gpu,
+               enum adreno_regs offset_name)
+{
+       if (offset_name >= REG_ADRENO_REGISTER_MAX ||
+                       !gpu->reg_offsets[offset_name]) {
+               BUG();
+       }
+       return true;
+}
+
+static inline u32 adreno_gpu_read(struct adreno_gpu *gpu,
+               enum adreno_regs offset_name)
+{
+       u32 reg = gpu->reg_offsets[offset_name];
+       u32 val = 0;
+       if(adreno_reg_check(gpu,offset_name))
+               val = gpu_read(&gpu->base, reg - 1);
+       return val;
+}
+
+static inline void adreno_gpu_write(struct adreno_gpu *gpu,
+               enum adreno_regs offset_name, u32 data)
+{
+       u32 reg = gpu->reg_offsets[offset_name];
+       if(adreno_reg_check(gpu, offset_name))
+               gpu_write(&gpu->base, reg - 1, data);
+}
 
 #endif /* __ADRENO_GPU_H__ */
index 6ef43f66c30a37676b9231d8f9b202b5f50c49f3..6a75cee94d811fdb12285e131e3187e113624096 100644 (file)
@@ -11,10 +11,10 @@ The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (   9859 bytes, from 2014-06-02 15:21:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  14960 bytes, from 2014-07-27 17:22:13)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  58020 bytes, from 2014-08-01 12:22:48)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  41068 bytes, from 2014-08-01 12:22:48)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2014-11-13 22:44:30)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  15053 bytes, from 2014-11-09 15:45:47)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  63169 bytes, from 2014-11-13 22:44:18)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  49097 bytes, from 2014-11-14 15:38:00)
 
 Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -157,6 +157,7 @@ enum adreno_pm4_type3_packets {
        CP_IM_STORE = 44,
        CP_SET_DRAW_INIT_FLAGS = 75,
        CP_SET_PROTECTED_MODE = 95,
+       CP_BOOTSTRAP_UCODE = 111,
        CP_LOAD_STATE = 48,
        CP_COND_INDIRECT_BUFFER_PFE = 58,
        CP_COND_INDIRECT_BUFFER_PFD = 50,
@@ -278,11 +279,11 @@ static inline uint32_t CP_DRAW_INDX_1_INDEX_SIZE(enum pc_di_index_size val)
 #define CP_DRAW_INDX_1_NOT_EOP                                 0x00001000
 #define CP_DRAW_INDX_1_SMALL_INDEX                             0x00002000
 #define CP_DRAW_INDX_1_PRE_DRAW_INITIATOR_ENABLE               0x00004000
-#define CP_DRAW_INDX_1_NUM_INDICES__MASK                       0xffff0000
-#define CP_DRAW_INDX_1_NUM_INDICES__SHIFT                      16
-static inline uint32_t CP_DRAW_INDX_1_NUM_INDICES(uint32_t val)
+#define CP_DRAW_INDX_1_NUM_INSTANCES__MASK                     0xff000000
+#define CP_DRAW_INDX_1_NUM_INSTANCES__SHIFT                    24
+static inline uint32_t CP_DRAW_INDX_1_NUM_INSTANCES(uint32_t val)
 {
-       return ((val) << CP_DRAW_INDX_1_NUM_INDICES__SHIFT) & CP_DRAW_INDX_1_NUM_INDICES__MASK;
+       return ((val) << CP_DRAW_INDX_1_NUM_INSTANCES__SHIFT) & CP_DRAW_INDX_1_NUM_INSTANCES__MASK;
 }
 
 #define REG_CP_DRAW_INDX_2                                     0x00000002
@@ -293,20 +294,20 @@ static inline uint32_t CP_DRAW_INDX_2_NUM_INDICES(uint32_t val)
        return ((val) << CP_DRAW_INDX_2_NUM_INDICES__SHIFT) & CP_DRAW_INDX_2_NUM_INDICES__MASK;
 }
 
-#define REG_CP_DRAW_INDX_2                                     0x00000002
-#define CP_DRAW_INDX_2_INDX_BASE__MASK                         0xffffffff
-#define CP_DRAW_INDX_2_INDX_BASE__SHIFT                                0
-static inline uint32_t CP_DRAW_INDX_2_INDX_BASE(uint32_t val)
+#define REG_CP_DRAW_INDX_3                                     0x00000003
+#define CP_DRAW_INDX_3_INDX_BASE__MASK                         0xffffffff
+#define CP_DRAW_INDX_3_INDX_BASE__SHIFT                                0
+static inline uint32_t CP_DRAW_INDX_3_INDX_BASE(uint32_t val)
 {
-       return ((val) << CP_DRAW_INDX_2_INDX_BASE__SHIFT) & CP_DRAW_INDX_2_INDX_BASE__MASK;
+       return ((val) << CP_DRAW_INDX_3_INDX_BASE__SHIFT) & CP_DRAW_INDX_3_INDX_BASE__MASK;
 }
 
-#define REG_CP_DRAW_INDX_2                                     0x00000002
-#define CP_DRAW_INDX_2_INDX_SIZE__MASK                         0xffffffff
-#define CP_DRAW_INDX_2_INDX_SIZE__SHIFT                                0
-static inline uint32_t CP_DRAW_INDX_2_INDX_SIZE(uint32_t val)
+#define REG_CP_DRAW_INDX_4                                     0x00000004
+#define CP_DRAW_INDX_4_INDX_SIZE__MASK                         0xffffffff
+#define CP_DRAW_INDX_4_INDX_SIZE__SHIFT                                0
+static inline uint32_t CP_DRAW_INDX_4_INDX_SIZE(uint32_t val)
 {
-       return ((val) << CP_DRAW_INDX_2_INDX_SIZE__SHIFT) & CP_DRAW_INDX_2_INDX_SIZE__MASK;
+       return ((val) << CP_DRAW_INDX_4_INDX_SIZE__SHIFT) & CP_DRAW_INDX_4_INDX_SIZE__MASK;
 }
 
 #define REG_CP_DRAW_INDX_2_0                                   0x00000000
@@ -345,11 +346,11 @@ static inline uint32_t CP_DRAW_INDX_2_1_INDEX_SIZE(enum pc_di_index_size val)
 #define CP_DRAW_INDX_2_1_NOT_EOP                               0x00001000
 #define CP_DRAW_INDX_2_1_SMALL_INDEX                           0x00002000
 #define CP_DRAW_INDX_2_1_PRE_DRAW_INITIATOR_ENABLE             0x00004000
-#define CP_DRAW_INDX_2_1_NUM_INDICES__MASK                     0xffff0000
-#define CP_DRAW_INDX_2_1_NUM_INDICES__SHIFT                    16
-static inline uint32_t CP_DRAW_INDX_2_1_NUM_INDICES(uint32_t val)
+#define CP_DRAW_INDX_2_1_NUM_INSTANCES__MASK                   0xff000000
+#define CP_DRAW_INDX_2_1_NUM_INSTANCES__SHIFT                  24
+static inline uint32_t CP_DRAW_INDX_2_1_NUM_INSTANCES(uint32_t val)
 {
-       return ((val) << CP_DRAW_INDX_2_1_NUM_INDICES__SHIFT) & CP_DRAW_INDX_2_1_NUM_INDICES__MASK;
+       return ((val) << CP_DRAW_INDX_2_1_NUM_INSTANCES__SHIFT) & CP_DRAW_INDX_2_1_NUM_INSTANCES__MASK;
 }
 
 #define REG_CP_DRAW_INDX_2_2                                   0x00000002
@@ -388,11 +389,11 @@ static inline uint32_t CP_DRAW_INDX_OFFSET_0_INDEX_SIZE(enum pc_di_index_size va
 #define CP_DRAW_INDX_OFFSET_0_NOT_EOP                          0x00001000
 #define CP_DRAW_INDX_OFFSET_0_SMALL_INDEX                      0x00002000
 #define CP_DRAW_INDX_OFFSET_0_PRE_DRAW_INITIATOR_ENABLE                0x00004000
-#define CP_DRAW_INDX_OFFSET_0_NUM_INDICES__MASK                        0xffff0000
-#define CP_DRAW_INDX_OFFSET_0_NUM_INDICES__SHIFT               16
-static inline uint32_t CP_DRAW_INDX_OFFSET_0_NUM_INDICES(uint32_t val)
+#define CP_DRAW_INDX_OFFSET_0_NUM_INSTANCES__MASK              0xffff0000
+#define CP_DRAW_INDX_OFFSET_0_NUM_INSTANCES__SHIFT             16
+static inline uint32_t CP_DRAW_INDX_OFFSET_0_NUM_INSTANCES(uint32_t val)
 {
-       return ((val) << CP_DRAW_INDX_OFFSET_0_NUM_INDICES__SHIFT) & CP_DRAW_INDX_OFFSET_0_NUM_INDICES__MASK;
+       return ((val) << CP_DRAW_INDX_OFFSET_0_NUM_INSTANCES__SHIFT) & CP_DRAW_INDX_OFFSET_0_NUM_INSTANCES__MASK;
 }
 
 #define REG_CP_DRAW_INDX_OFFSET_1                              0x00000001
@@ -405,20 +406,22 @@ static inline uint32_t CP_DRAW_INDX_OFFSET_2_NUM_INDICES(uint32_t val)
        return ((val) << CP_DRAW_INDX_OFFSET_2_NUM_INDICES__SHIFT) & CP_DRAW_INDX_OFFSET_2_NUM_INDICES__MASK;
 }
 
-#define REG_CP_DRAW_INDX_OFFSET_2                              0x00000002
-#define CP_DRAW_INDX_OFFSET_2_INDX_BASE__MASK                  0xffffffff
-#define CP_DRAW_INDX_OFFSET_2_INDX_BASE__SHIFT                 0
-static inline uint32_t CP_DRAW_INDX_OFFSET_2_INDX_BASE(uint32_t val)
+#define REG_CP_DRAW_INDX_OFFSET_3                              0x00000003
+
+#define REG_CP_DRAW_INDX_OFFSET_4                              0x00000004
+#define CP_DRAW_INDX_OFFSET_4_INDX_BASE__MASK                  0xffffffff
+#define CP_DRAW_INDX_OFFSET_4_INDX_BASE__SHIFT                 0
+static inline uint32_t CP_DRAW_INDX_OFFSET_4_INDX_BASE(uint32_t val)
 {
-       return ((val) << CP_DRAW_INDX_OFFSET_2_INDX_BASE__SHIFT) & CP_DRAW_INDX_OFFSET_2_INDX_BASE__MASK;
+       return ((val) << CP_DRAW_INDX_OFFSET_4_INDX_BASE__SHIFT) & CP_DRAW_INDX_OFFSET_4_INDX_BASE__MASK;
 }
 
-#define REG_CP_DRAW_INDX_OFFSET_2                              0x00000002
-#define CP_DRAW_INDX_OFFSET_2_INDX_SIZE__MASK                  0xffffffff
-#define CP_DRAW_INDX_OFFSET_2_INDX_SIZE__SHIFT                 0
-static inline uint32_t CP_DRAW_INDX_OFFSET_2_INDX_SIZE(uint32_t val)
+#define REG_CP_DRAW_INDX_OFFSET_5                              0x00000005
+#define CP_DRAW_INDX_OFFSET_5_INDX_SIZE__MASK                  0xffffffff
+#define CP_DRAW_INDX_OFFSET_5_INDX_SIZE__SHIFT                 0
+static inline uint32_t CP_DRAW_INDX_OFFSET_5_INDX_SIZE(uint32_t val)
 {
-       return ((val) << CP_DRAW_INDX_OFFSET_2_INDX_SIZE__SHIFT) & CP_DRAW_INDX_OFFSET_2_INDX_SIZE__MASK;
+       return ((val) << CP_DRAW_INDX_OFFSET_5_INDX_SIZE__SHIFT) & CP_DRAW_INDX_OFFSET_5_INDX_SIZE__MASK;
 }
 
 #define REG_CP_SET_DRAW_STATE_0                                        0x00000000
index e965898dfda6cbc2b09876fe3a9f8b68582d8fc5..448438b759b4eeb41af628913c09ecca4f1e0f2a 100644 (file)
@@ -10,12 +10,12 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20457 bytes, from 2014-08-01 12:22:48)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2014-07-17 15:34:33)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-07-17 15:34:33)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20136 bytes, from 2014-10-31 16:51:39)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1940 bytes, from 2014-10-31 16:51:39)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  23963 bytes, from 2014-10-31 16:51:46)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-08-01 12:23:53)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
 
index f2bdda957205a092b4d4a0bd6f02cfcd0d32fdb6..c102a7f074acdd5936cc99b9c46fbddffffbaa5a 100644 (file)
@@ -10,12 +10,12 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20457 bytes, from 2014-08-01 12:22:48)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2014-07-17 15:34:33)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-07-17 15:34:33)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20136 bytes, from 2014-10-31 16:51:39)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1940 bytes, from 2014-10-31 16:51:39)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  23963 bytes, from 2014-10-31 16:51:46)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-08-01 12:23:53)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
 
index e5b071ffd8657761d78f8499f86eb5c4e825144b..a900134bdf3300b38ac911805b825f3e683b5923 100644 (file)
@@ -10,12 +10,12 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20457 bytes, from 2014-08-01 12:22:48)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2014-07-17 15:34:33)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-07-17 15:34:33)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20136 bytes, from 2014-10-31 16:51:39)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1940 bytes, from 2014-10-31 16:51:39)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  23963 bytes, from 2014-10-31 16:51:46)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-08-01 12:23:53)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
 
index 9d00dcba695950873c77baa761dea89e4b86aeac..062c687253766278e69fe46429cc927c3223cada 100644 (file)
@@ -15,6 +15,7 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/of_irq.h>
 #include "hdmi.h"
 
 void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
@@ -39,7 +40,7 @@ void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
                        power_on ? "Enable" : "Disable", ctrl);
 }
 
-irqreturn_t hdmi_irq(int irq, void *dev_id)
+static irqreturn_t hdmi_irq(int irq, void *dev_id)
 {
        struct hdmi *hdmi = dev_id;
 
@@ -54,9 +55,8 @@ irqreturn_t hdmi_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-void hdmi_destroy(struct kref *kref)
+static void hdmi_destroy(struct hdmi *hdmi)
 {
-       struct hdmi *hdmi = container_of(kref, struct hdmi, refcount);
        struct hdmi_phy *phy = hdmi->phy;
 
        if (phy)
@@ -68,37 +68,24 @@ void hdmi_destroy(struct kref *kref)
        platform_set_drvdata(hdmi->pdev, NULL);
 }
 
-/* initialize connector */
-struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
+/* construct hdmi at bind/probe time, grab all the resources.  If
+ * we are to EPROBE_DEFER we want to do it here, rather than later
+ * at modeset_init() time
+ */
+static struct hdmi *hdmi_init(struct platform_device *pdev)
 {
+       struct hdmi_platform_config *config = pdev->dev.platform_data;
        struct hdmi *hdmi = NULL;
-       struct msm_drm_private *priv = dev->dev_private;
-       struct platform_device *pdev = priv->hdmi_pdev;
-       struct hdmi_platform_config *config;
        int i, ret;
 
-       if (!pdev) {
-               dev_err(dev->dev, "no hdmi device\n");
-               ret = -ENXIO;
-               goto fail;
-       }
-
-       config = pdev->dev.platform_data;
-
-       hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
+       hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
        if (!hdmi) {
                ret = -ENOMEM;
                goto fail;
        }
 
-       kref_init(&hdmi->refcount);
-
-       hdmi->dev = dev;
        hdmi->pdev = pdev;
        hdmi->config = config;
-       hdmi->encoder = encoder;
-
-       hdmi_audio_infoframe_init(&hdmi->audio.infoframe);
 
        /* not sure about which phy maps to which msm.. probably I miss some */
        if (config->phy_init)
@@ -108,7 +95,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
 
        if (IS_ERR(hdmi->phy)) {
                ret = PTR_ERR(hdmi->phy);
-               dev_err(dev->dev, "failed to load phy: %d\n", ret);
+               dev_err(&pdev->dev, "failed to load phy: %d\n", ret);
                hdmi->phy = NULL;
                goto fail;
        }
@@ -127,7 +114,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
                                config->hpd_reg_names[i]);
                if (IS_ERR(reg)) {
                        ret = PTR_ERR(reg);
-                       dev_err(dev->dev, "failed to get hpd regulator: %s (%d)\n",
+                       dev_err(&pdev->dev, "failed to get hpd regulator: %s (%d)\n",
                                        config->hpd_reg_names[i], ret);
                        goto fail;
                }
@@ -143,7 +130,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
                                config->pwr_reg_names[i]);
                if (IS_ERR(reg)) {
                        ret = PTR_ERR(reg);
-                       dev_err(dev->dev, "failed to get pwr regulator: %s (%d)\n",
+                       dev_err(&pdev->dev, "failed to get pwr regulator: %s (%d)\n",
                                        config->pwr_reg_names[i], ret);
                        goto fail;
                }
@@ -158,7 +145,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
                clk = devm_clk_get(&pdev->dev, config->hpd_clk_names[i]);
                if (IS_ERR(clk)) {
                        ret = PTR_ERR(clk);
-                       dev_err(dev->dev, "failed to get hpd clk: %s (%d)\n",
+                       dev_err(&pdev->dev, "failed to get hpd clk: %s (%d)\n",
                                        config->hpd_clk_names[i], ret);
                        goto fail;
                }
@@ -173,7 +160,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
                clk = devm_clk_get(&pdev->dev, config->pwr_clk_names[i]);
                if (IS_ERR(clk)) {
                        ret = PTR_ERR(clk);
-                       dev_err(dev->dev, "failed to get pwr clk: %s (%d)\n",
+                       dev_err(&pdev->dev, "failed to get pwr clk: %s (%d)\n",
                                        config->pwr_clk_names[i], ret);
                        goto fail;
                }
@@ -184,11 +171,40 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
        hdmi->i2c = hdmi_i2c_init(hdmi);
        if (IS_ERR(hdmi->i2c)) {
                ret = PTR_ERR(hdmi->i2c);
-               dev_err(dev->dev, "failed to get i2c: %d\n", ret);
+               dev_err(&pdev->dev, "failed to get i2c: %d\n", ret);
                hdmi->i2c = NULL;
                goto fail;
        }
 
+       return hdmi;
+
+fail:
+       if (hdmi)
+               hdmi_destroy(hdmi);
+
+       return ERR_PTR(ret);
+}
+
+/* Second part of initialization, the drm/kms level modeset_init,
+ * constructs/initializes mode objects, etc, is called from master
+ * driver (not hdmi sub-device's probe/bind!)
+ *
+ * Any resource (regulator/clk/etc) which could be missing at boot
+ * should be handled in hdmi_init() so that failure happens from
+ * hdmi sub-device's probe.
+ */
+int hdmi_modeset_init(struct hdmi *hdmi,
+               struct drm_device *dev, struct drm_encoder *encoder)
+{
+       struct msm_drm_private *priv = dev->dev_private;
+       struct platform_device *pdev = hdmi->pdev;
+       int ret;
+
+       hdmi->dev = dev;
+       hdmi->encoder = encoder;
+
+       hdmi_audio_infoframe_init(&hdmi->audio.infoframe);
+
        hdmi->bridge = hdmi_bridge_init(hdmi);
        if (IS_ERR(hdmi->bridge)) {
                ret = PTR_ERR(hdmi->bridge);
@@ -205,22 +221,20 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
                goto fail;
        }
 
-       if (!config->shared_irq) {
-               hdmi->irq = platform_get_irq(pdev, 0);
-               if (hdmi->irq < 0) {
-                       ret = hdmi->irq;
-                       dev_err(dev->dev, "failed to get irq: %d\n", ret);
-                       goto fail;
-               }
+       hdmi->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+       if (hdmi->irq < 0) {
+               ret = hdmi->irq;
+               dev_err(dev->dev, "failed to get irq: %d\n", ret);
+               goto fail;
+       }
 
-               ret = devm_request_threaded_irq(&pdev->dev, hdmi->irq,
-                               NULL, hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
-                               "hdmi_isr", hdmi);
-               if (ret < 0) {
-                       dev_err(dev->dev, "failed to request IRQ%u: %d\n",
-                                       hdmi->irq, ret);
-                       goto fail;
-               }
+       ret = devm_request_irq(&pdev->dev, hdmi->irq,
+                       hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+                       "hdmi_isr", hdmi);
+       if (ret < 0) {
+               dev_err(dev->dev, "failed to request IRQ%u: %d\n",
+                               hdmi->irq, ret);
+               goto fail;
        }
 
        encoder->bridge = hdmi->bridge;
@@ -230,19 +244,20 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
 
        platform_set_drvdata(pdev, hdmi);
 
-       return hdmi;
+       return 0;
 
 fail:
-       if (hdmi) {
-               /* bridge/connector are normally destroyed by drm: */
-               if (hdmi->bridge)
-                       hdmi->bridge->funcs->destroy(hdmi->bridge);
-               if (hdmi->connector)
-                       hdmi->connector->funcs->destroy(hdmi->connector);
-               hdmi_destroy(&hdmi->refcount);
+       /* bridge/connector are normally destroyed by drm: */
+       if (hdmi->bridge) {
+               hdmi->bridge->funcs->destroy(hdmi->bridge);
+               hdmi->bridge = NULL;
+       }
+       if (hdmi->connector) {
+               hdmi->connector->funcs->destroy(hdmi->connector);
+               hdmi->connector = NULL;
        }
 
-       return ERR_PTR(ret);
+       return ret;
 }
 
 /*
@@ -251,13 +266,6 @@ fail:
 
 #include <linux/of_gpio.h>
 
-static void set_hdmi_pdev(struct drm_device *dev,
-               struct platform_device *pdev)
-{
-       struct msm_drm_private *priv = dev->dev_private;
-       priv->hdmi_pdev = pdev;
-}
-
 #ifdef CONFIG_OF
 static int get_gpio(struct device *dev, struct device_node *of_node, const char *name)
 {
@@ -278,7 +286,10 @@ static int get_gpio(struct device *dev, struct device_node *of_node, const char
 
 static int hdmi_bind(struct device *dev, struct device *master, void *data)
 {
+       struct drm_device *drm = dev_get_drvdata(master);
+       struct msm_drm_private *priv = drm->dev_private;
        static struct hdmi_platform_config config = {};
+       struct hdmi *hdmi;
 #ifdef CONFIG_OF
        struct device_node *of_node = dev->of_node;
 
@@ -298,7 +309,6 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
                config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names);
                config.pwr_clk_names = pwr_clk_names;
                config.pwr_clk_cnt   = ARRAY_SIZE(pwr_clk_names);
-               config.shared_irq    = true;
        } else if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8960")) {
                static const char *hpd_clk_names[] = {"core_clk", "master_iface_clk", "slave_iface_clk"};
                static const char *hpd_reg_names[] = {"core-vdda", "hdmi-mux"};
@@ -369,14 +379,22 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
        }
 #endif
        dev->platform_data = &config;
-       set_hdmi_pdev(dev_get_drvdata(master), to_platform_device(dev));
+       hdmi = hdmi_init(to_platform_device(dev));
+       if (IS_ERR(hdmi))
+               return PTR_ERR(hdmi);
+       priv->hdmi = hdmi;
        return 0;
 }
 
 static void hdmi_unbind(struct device *dev, struct device *master,
                void *data)
 {
-       set_hdmi_pdev(dev_get_drvdata(master), NULL);
+       struct drm_device *drm = dev_get_drvdata(master);
+       struct msm_drm_private *priv = drm->dev_private;
+       if (priv->hdmi) {
+               hdmi_destroy(priv->hdmi);
+               priv->hdmi = NULL;
+       }
 }
 
 static const struct component_ops hdmi_ops = {
index b981995410b50a886e21f74e38589d6af415f950..43e654f751b741a06578989b121d225139a3664a 100644 (file)
@@ -38,8 +38,6 @@ struct hdmi_audio {
 };
 
 struct hdmi {
-       struct kref refcount;
-
        struct drm_device *dev;
        struct platform_device *pdev;
 
@@ -97,13 +95,9 @@ struct hdmi_platform_config {
        /* gpio's: */
        int ddc_clk_gpio, ddc_data_gpio, hpd_gpio, mux_en_gpio, mux_sel_gpio;
        int mux_lpm_gpio;
-
-       /* older devices had their own irq, mdp5+ it is shared w/ mdp: */
-       bool shared_irq;
 };
 
 void hdmi_set_mode(struct hdmi *hdmi, bool power_on);
-void hdmi_destroy(struct kref *kref);
 
 static inline void hdmi_write(struct hdmi *hdmi, u32 reg, u32 data)
 {
@@ -115,17 +109,6 @@ static inline u32 hdmi_read(struct hdmi *hdmi, u32 reg)
        return msm_readl(hdmi->mmio + reg);
 }
 
-static inline struct hdmi * hdmi_reference(struct hdmi *hdmi)
-{
-       kref_get(&hdmi->refcount);
-       return hdmi;
-}
-
-static inline void hdmi_unreference(struct hdmi *hdmi)
-{
-       kref_put(&hdmi->refcount, hdmi_destroy);
-}
-
 /*
  * The phy appears to be different, for example between 8960 and 8x60,
  * so split the phy related functions out and load the correct one at
index 76fd0cfc6558fc622755ca90ff4c3fbc9a4f17ea..5b0844befbab6b42b268dad38f8d864138adec01 100644 (file)
@@ -10,12 +10,12 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20457 bytes, from 2014-08-01 12:22:48)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2014-07-17 15:34:33)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-07-17 15:34:33)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20136 bytes, from 2014-10-31 16:51:39)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1940 bytes, from 2014-10-31 16:51:39)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  23963 bytes, from 2014-10-31 16:51:46)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-08-01 12:23:53)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
 
index f6cf745c249e60a604e8ab00f99ca75cb3af2b43..6902ad6da710fe2d4f7fb7e9f56c3f84ba1c5b49 100644 (file)
@@ -26,7 +26,6 @@ struct hdmi_bridge {
 static void hdmi_bridge_destroy(struct drm_bridge *bridge)
 {
        struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
-       hdmi_unreference(hdmi_bridge->hdmi);
        drm_bridge_cleanup(bridge);
        kfree(hdmi_bridge);
 }
@@ -218,7 +217,7 @@ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi)
                goto fail;
        }
 
-       hdmi_bridge->hdmi = hdmi_reference(hdmi);
+       hdmi_bridge->hdmi = hdmi;
 
        bridge = &hdmi_bridge->base;
 
index 4aca2a3c667cff443495f14508c5acdf7a7b0a48..fbebb0405d76d7df217c1772a26cc43e78578b29 100644 (file)
@@ -330,8 +330,6 @@ static void hdmi_connector_destroy(struct drm_connector *connector)
        drm_connector_unregister(connector);
        drm_connector_cleanup(connector);
 
-       hdmi_unreference(hdmi_connector->hdmi);
-
        kfree(hdmi_connector);
 }
 
@@ -401,6 +399,9 @@ static const struct drm_connector_funcs hdmi_connector_funcs = {
        .detect = hdmi_connector_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .destroy = hdmi_connector_destroy,
+       .reset = drm_atomic_helper_connector_reset,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
@@ -422,7 +423,7 @@ struct drm_connector *hdmi_connector_init(struct hdmi *hdmi)
                goto fail;
        }
 
-       hdmi_connector->hdmi = hdmi_reference(hdmi);
+       hdmi_connector->hdmi = hdmi;
        INIT_WORK(&hdmi_connector->hpd_work, hotplug_work);
 
        connector = &hdmi_connector->base;
index f408b69486a8eb83d299abc636356187d2d467bb..eeed006eed1337a6c07c62e0cc62d944b95fce83 100644 (file)
@@ -510,7 +510,7 @@ struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi)
 
 #ifdef CONFIG_COMMON_CLK
        phy_8960->pll_hw.init = &pll_init;
-       phy_8960->pll = devm_clk_register(hdmi->dev->dev, &phy_8960->pll_hw);
+       phy_8960->pll = devm_clk_register(&hdmi->pdev->dev, &phy_8960->pll_hw);
        if (IS_ERR(phy_8960->pll)) {
                ret = PTR_ERR(phy_8960->pll);
                phy_8960->pll = NULL;
index d53c29327df908c81e957467803ce0d6d6ad3ece..29bd796797de6e240d4749fd2b6d8623b1a592d9 100644 (file)
@@ -10,12 +10,12 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20457 bytes, from 2014-08-01 12:22:48)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2014-07-17 15:34:33)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-07-17 15:34:33)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20136 bytes, from 2014-10-31 16:51:39)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1940 bytes, from 2014-10-31 16:51:39)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  23963 bytes, from 2014-10-31 16:51:46)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-08-01 12:23:53)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
 
index 03c0bd9cd5b9270dcec078aaa71ce7be2adff210..a4a7f8c7122acfcb93a9a68b52af9ab4847fa023 100644 (file)
@@ -10,12 +10,12 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20457 bytes, from 2014-08-01 12:22:48)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2014-07-17 15:34:33)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-07-17 15:34:33)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20136 bytes, from 2014-10-31 16:51:39)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1940 bytes, from 2014-10-31 16:51:39)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  23963 bytes, from 2014-10-31 16:51:46)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-08-01 12:23:53)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
 
index 7d00f7fb5773571c2fd005df0e278c18de425b64..a7672e100d8b5bd5f4ac4b782a3b1d0a38197a79 100644 (file)
@@ -25,8 +25,6 @@
 struct mdp4_crtc {
        struct drm_crtc base;
        char name[8];
-       struct drm_plane *plane;
-       struct drm_plane *planes[8];
        int id;
        int ovlp;
        enum mdp4_dma dma;
@@ -52,25 +50,11 @@ struct mdp4_crtc {
 
        /* if there is a pending flip, these will be non-null: */
        struct drm_pending_vblank_event *event;
-       struct msm_fence_cb pageflip_cb;
 
 #define PENDING_CURSOR 0x1
 #define PENDING_FLIP   0x2
        atomic_t pending;
 
-       /* the fb that we logically (from PoV of KMS API) hold a ref
-        * to.  Which we may not yet be scanning out (we may still
-        * be scanning out previous in case of page_flip while waiting
-        * for gpu rendering to complete:
-        */
-       struct drm_framebuffer *fb;
-
-       /* the fb that we currently hold a scanout ref to: */
-       struct drm_framebuffer *scanout_fb;
-
-       /* for unref'ing framebuffers after scanout completes: */
-       struct drm_flip_work unref_fb_work;
-
        /* for unref'ing cursor bo's after scanout completes: */
        struct drm_flip_work unref_cursor_work;
 
@@ -97,15 +81,14 @@ static void crtc_flush(struct drm_crtc *crtc)
 {
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
        struct mdp4_kms *mdp4_kms = get_kms(crtc);
-       uint32_t i, flush = 0;
+       struct drm_plane *plane;
+       uint32_t flush = 0;
 
-       for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) {
-               struct drm_plane *plane = mdp4_crtc->planes[i];
-               if (plane) {
-                       enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
-                       flush |= pipe2flush(pipe_id);
-               }
+       drm_atomic_crtc_for_each_plane(plane, crtc) {
+               enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
+               flush |= pipe2flush(pipe_id);
        }
+
        flush |= ovlp2flush(mdp4_crtc->ovlp);
 
        DBG("%s: flush=%08x", mdp4_crtc->name, flush);
@@ -113,47 +96,6 @@ static void crtc_flush(struct drm_crtc *crtc)
        mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush);
 }
 
-static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb)
-{
-       struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-       struct drm_framebuffer *old_fb = mdp4_crtc->fb;
-
-       /* grab reference to incoming scanout fb: */
-       drm_framebuffer_reference(new_fb);
-       mdp4_crtc->base.primary->fb = new_fb;
-       mdp4_crtc->fb = new_fb;
-
-       if (old_fb)
-               drm_flip_work_queue(&mdp4_crtc->unref_fb_work, old_fb);
-}
-
-/* unlike update_fb(), take a ref to the new scanout fb *before* updating
- * plane, then call this.  Needed to ensure we don't unref the buffer that
- * is actually still being scanned out.
- *
- * Note that this whole thing goes away with atomic.. since we can defer
- * calling into driver until rendering is done.
- */
-static void update_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb)
-{
-       struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-
-       /* flush updates, to make sure hw is updated to new scanout fb,
-        * so that we can safely queue unref to current fb (ie. next
-        * vblank we know hw is done w/ previous scanout_fb).
-        */
-       crtc_flush(crtc);
-
-       if (mdp4_crtc->scanout_fb)
-               drm_flip_work_queue(&mdp4_crtc->unref_fb_work,
-                               mdp4_crtc->scanout_fb);
-
-       mdp4_crtc->scanout_fb = fb;
-
-       /* enable vblank to complete flip: */
-       request_pending(crtc, PENDING_FLIP);
-}
-
 /* if file!=NULL, this is preclose potential cancel-flip path */
 static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
 {
@@ -171,38 +113,13 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
                 */
                if (!file || (event->base.file_priv == file)) {
                        mdp4_crtc->event = NULL;
+                       DBG("%s: send event: %p", mdp4_crtc->name, event);
                        drm_send_vblank_event(dev, mdp4_crtc->id, event);
                }
        }
        spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
-static void pageflip_cb(struct msm_fence_cb *cb)
-{
-       struct mdp4_crtc *mdp4_crtc =
-               container_of(cb, struct mdp4_crtc, pageflip_cb);
-       struct drm_crtc *crtc = &mdp4_crtc->base;
-       struct drm_framebuffer *fb = crtc->primary->fb;
-
-       if (!fb)
-               return;
-
-       drm_framebuffer_reference(fb);
-       mdp4_plane_set_scanout(mdp4_crtc->plane, fb);
-       update_scanout(crtc, fb);
-}
-
-static void unref_fb_worker(struct drm_flip_work *work, void *val)
-{
-       struct mdp4_crtc *mdp4_crtc =
-               container_of(work, struct mdp4_crtc, unref_fb_work);
-       struct drm_device *dev = mdp4_crtc->base.dev;
-
-       mutex_lock(&dev->mode_config.mutex);
-       drm_framebuffer_unreference(val);
-       mutex_unlock(&dev->mode_config.mutex);
-}
-
 static void unref_cursor_worker(struct drm_flip_work *work, void *val)
 {
        struct mdp4_crtc *mdp4_crtc =
@@ -218,7 +135,6 @@ static void mdp4_crtc_destroy(struct drm_crtc *crtc)
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
 
        drm_crtc_cleanup(crtc);
-       drm_flip_work_cleanup(&mdp4_crtc->unref_fb_work);
        drm_flip_work_cleanup(&mdp4_crtc->unref_cursor_work);
 
        kfree(mdp4_crtc);
@@ -251,57 +167,70 @@ static bool mdp4_crtc_mode_fixup(struct drm_crtc *crtc,
        return true;
 }
 
-static void blend_setup(struct drm_crtc *crtc)
+/* statically (for now) map planes to mixer stage (z-order): */
+static const int idxs[] = {
+               [VG1]  = 1,
+               [VG2]  = 2,
+               [RGB1] = 0,
+               [RGB2] = 0,
+               [RGB3] = 0,
+               [VG3]  = 3,
+               [VG4]  = 4,
+
+};
+
+/* setup mixer config, for which we need to consider all crtc's and
+ * the planes attached to them
+ *
+ * TODO may possibly need some extra locking here
+ */
+static void setup_mixer(struct mdp4_kms *mdp4_kms)
 {
-       struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-       struct mdp4_kms *mdp4_kms = get_kms(crtc);
-       int i, ovlp = mdp4_crtc->ovlp;
+       struct drm_mode_config *config = &mdp4_kms->dev->mode_config;
+       struct drm_crtc *crtc;
        uint32_t mixer_cfg = 0;
        static const enum mdp_mixer_stage_id stages[] = {
                        STAGE_BASE, STAGE0, STAGE1, STAGE2, STAGE3,
        };
-       /* statically (for now) map planes to mixer stage (z-order): */
-       static const int idxs[] = {
-                       [VG1]  = 1,
-                       [VG2]  = 2,
-                       [RGB1] = 0,
-                       [RGB2] = 0,
-                       [RGB3] = 0,
-                       [VG3]  = 3,
-                       [VG4]  = 4,
 
-       };
-       bool alpha[4]= { false, false, false, false };
+       list_for_each_entry(crtc, &config->crtc_list, head) {
+               struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+               struct drm_plane *plane;
 
-       /* Don't rely on value read back from hw, but instead use our
-        * own shadowed value.  Possibly disable/reenable looses the
-        * previous value and goes back to power-on default?
-        */
-       mixer_cfg = mdp4_kms->mixer_cfg;
+               drm_atomic_crtc_for_each_plane(plane, crtc) {
+                       enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
+                       int idx = idxs[pipe_id];
+                       mixer_cfg = mixercfg(mixer_cfg, mdp4_crtc->mixer,
+                                       pipe_id, stages[idx]);
+               }
+       }
+
+       mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, mixer_cfg);
+}
+
+static void blend_setup(struct drm_crtc *crtc)
+{
+       struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+       struct mdp4_kms *mdp4_kms = get_kms(crtc);
+       struct drm_plane *plane;
+       int i, ovlp = mdp4_crtc->ovlp;
+       bool alpha[4]= { false, false, false, false };
 
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW0(ovlp), 0);
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW1(ovlp), 0);
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0);
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH1(ovlp), 0);
 
-       for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) {
-               struct drm_plane *plane = mdp4_crtc->planes[i];
-               if (plane) {
-                       enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
-                       int idx = idxs[pipe_id];
-                       if (idx > 0) {
-                               const struct mdp_format *format =
+       drm_atomic_crtc_for_each_plane(plane, crtc) {
+               enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
+               int idx = idxs[pipe_id];
+               if (idx > 0) {
+                       const struct mdp_format *format =
                                        to_mdp_format(msm_framebuffer_format(plane->fb));
-                               alpha[idx-1] = format->alpha_enable;
-                       }
-                       mixer_cfg = mixercfg(mixer_cfg, mdp4_crtc->mixer,
-                                       pipe_id, stages[idx]);
+                       alpha[idx-1] = format->alpha_enable;
                }
        }
 
-       /* this shouldn't happen.. and seems to cause underflow: */
-       WARN_ON(!mixer_cfg);
-
        for (i = 0; i < 4; i++) {
                uint32_t op;
 
@@ -324,22 +253,21 @@ static void blend_setup(struct drm_crtc *crtc)
                mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(ovlp, i), 0);
        }
 
-       mdp4_kms->mixer_cfg = mixer_cfg;
-       mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, mixer_cfg);
+       setup_mixer(mdp4_kms);
 }
 
-static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
-               struct drm_display_mode *mode,
-               struct drm_display_mode *adjusted_mode,
-               int x, int y,
-               struct drm_framebuffer *old_fb)
+static void mdp4_crtc_mode_set_nofb(struct drm_crtc *crtc)
 {
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
        struct mdp4_kms *mdp4_kms = get_kms(crtc);
        enum mdp4_dma dma = mdp4_crtc->dma;
-       int ret, ovlp = mdp4_crtc->ovlp;
+       int ovlp = mdp4_crtc->ovlp;
+       struct drm_display_mode *mode;
+
+       if (WARN_ON(!crtc->state))
+               return;
 
-       mode = adjusted_mode;
+       mode = &crtc->state->adjusted_mode;
 
        DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
                        mdp4_crtc->name, mode->base.id, mode->name,
@@ -350,28 +278,13 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
                        mode->vsync_end, mode->vtotal,
                        mode->type, mode->flags);
 
-       /* grab extra ref for update_scanout() */
-       drm_framebuffer_reference(crtc->primary->fb);
-
-       ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->primary->fb,
-                       0, 0, mode->hdisplay, mode->vdisplay,
-                       x << 16, y << 16,
-                       mode->hdisplay << 16, mode->vdisplay << 16);
-       if (ret) {
-               drm_framebuffer_unreference(crtc->primary->fb);
-               dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
-                               mdp4_crtc->name, ret);
-               return ret;
-       }
-
        mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_SIZE(dma),
                        MDP4_DMA_SRC_SIZE_WIDTH(mode->hdisplay) |
                        MDP4_DMA_SRC_SIZE_HEIGHT(mode->vdisplay));
 
        /* take data from pipe: */
        mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_BASE(dma), 0);
-       mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_STRIDE(dma),
-                       crtc->primary->fb->pitches[0]);
+       mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_STRIDE(dma), 0);
        mdp4_write(mdp4_kms, REG_MDP4_DMA_DST_SIZE(dma),
                        MDP4_DMA_DST_SIZE_WIDTH(0) |
                        MDP4_DMA_DST_SIZE_HEIGHT(0));
@@ -380,8 +293,7 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_SIZE(ovlp),
                        MDP4_OVLP_SIZE_WIDTH(mode->hdisplay) |
                        MDP4_OVLP_SIZE_HEIGHT(mode->vdisplay));
-       mdp4_write(mdp4_kms, REG_MDP4_OVLP_STRIDE(ovlp),
-                       crtc->primary->fb->pitches[0]);
+       mdp4_write(mdp4_kms, REG_MDP4_OVLP_STRIDE(ovlp), 0);
 
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1);
 
@@ -390,11 +302,6 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
                mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(1), 0x00ff0000);
                mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000);
        }
-
-       update_fb(crtc, crtc->primary->fb);
-       update_scanout(crtc, crtc->primary->fb);
-
-       return 0;
 }
 
 static void mdp4_crtc_prepare(struct drm_crtc *crtc)
@@ -416,60 +323,51 @@ static void mdp4_crtc_commit(struct drm_crtc *crtc)
        drm_crtc_vblank_put(crtc);
 }
 
-static int mdp4_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
-               struct drm_framebuffer *old_fb)
+static void mdp4_crtc_load_lut(struct drm_crtc *crtc)
+{
+}
+
+static int mdp4_crtc_atomic_check(struct drm_crtc *crtc,
+               struct drm_crtc_state *state)
 {
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-       struct drm_plane *plane = mdp4_crtc->plane;
-       struct drm_display_mode *mode = &crtc->mode;
-       int ret;
+       struct drm_device *dev = crtc->dev;
 
-       /* grab extra ref for update_scanout() */
-       drm_framebuffer_reference(crtc->primary->fb);
+       DBG("%s: check", mdp4_crtc->name);
 
-       ret = mdp4_plane_mode_set(plane, crtc, crtc->primary->fb,
-                       0, 0, mode->hdisplay, mode->vdisplay,
-                       x << 16, y << 16,
-                       mode->hdisplay << 16, mode->vdisplay << 16);
-       if (ret) {
-               drm_framebuffer_unreference(crtc->primary->fb);
-               return ret;
+       if (mdp4_crtc->event) {
+               dev_err(dev->dev, "already pending flip!\n");
+               return -EBUSY;
        }
 
-       update_fb(crtc, crtc->primary->fb);
-       update_scanout(crtc, crtc->primary->fb);
+       // TODO anything else to check?
 
        return 0;
 }
 
-static void mdp4_crtc_load_lut(struct drm_crtc *crtc)
+static void mdp4_crtc_atomic_begin(struct drm_crtc *crtc)
 {
+       struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+       DBG("%s: begin", mdp4_crtc->name);
 }
 
-static int mdp4_crtc_page_flip(struct drm_crtc *crtc,
-               struct drm_framebuffer *new_fb,
-               struct drm_pending_vblank_event *event,
-               uint32_t page_flip_flags)
+static void mdp4_crtc_atomic_flush(struct drm_crtc *crtc)
 {
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
        struct drm_device *dev = crtc->dev;
-       struct drm_gem_object *obj;
        unsigned long flags;
 
-       if (mdp4_crtc->event) {
-               dev_err(dev->dev, "already pending flip!\n");
-               return -EBUSY;
-       }
+       DBG("%s: flush", mdp4_crtc->name);
 
-       obj = msm_framebuffer_bo(new_fb, 0);
+       WARN_ON(mdp4_crtc->event);
 
        spin_lock_irqsave(&dev->event_lock, flags);
-       mdp4_crtc->event = event;
+       mdp4_crtc->event = crtc->state->event;
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
-       update_fb(crtc, new_fb);
-
-       return msm_gem_queue_inactive_cb(obj, &mdp4_crtc->pageflip_cb);
+       blend_setup(crtc);
+       crtc_flush(crtc);
+       request_pending(crtc, PENDING_FLIP);
 }
 
 static int mdp4_crtc_set_property(struct drm_crtc *crtc,
@@ -607,22 +505,29 @@ static int mdp4_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
 }
 
 static const struct drm_crtc_funcs mdp4_crtc_funcs = {
-       .set_config = drm_crtc_helper_set_config,
+       .set_config = drm_atomic_helper_set_config,
        .destroy = mdp4_crtc_destroy,
-       .page_flip = mdp4_crtc_page_flip,
+       .page_flip = drm_atomic_helper_page_flip,
        .set_property = mdp4_crtc_set_property,
        .cursor_set = mdp4_crtc_cursor_set,
        .cursor_move = mdp4_crtc_cursor_move,
+       .reset = drm_atomic_helper_crtc_reset,
+       .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
 };
 
 static const struct drm_crtc_helper_funcs mdp4_crtc_helper_funcs = {
        .dpms = mdp4_crtc_dpms,
        .mode_fixup = mdp4_crtc_mode_fixup,
-       .mode_set = mdp4_crtc_mode_set,
+       .mode_set_nofb = mdp4_crtc_mode_set_nofb,
+       .mode_set = drm_helper_crtc_mode_set,
+       .mode_set_base = drm_helper_crtc_mode_set_base,
        .prepare = mdp4_crtc_prepare,
        .commit = mdp4_crtc_commit,
-       .mode_set_base = mdp4_crtc_mode_set_base,
        .load_lut = mdp4_crtc_load_lut,
+       .atomic_check = mdp4_crtc_atomic_check,
+       .atomic_begin = mdp4_crtc_atomic_begin,
+       .atomic_flush = mdp4_crtc_atomic_flush,
 };
 
 static void mdp4_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
@@ -638,7 +543,6 @@ static void mdp4_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
 
        if (pending & PENDING_FLIP) {
                complete_flip(crtc, NULL);
-               drm_flip_work_commit(&mdp4_crtc->unref_fb_work, priv->wq);
        }
 
        if (pending & PENDING_CURSOR) {
@@ -663,7 +567,8 @@ uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc)
 
 void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file)
 {
-       DBG("cancel: %p", file);
+       struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+       DBG("%s: cancel: %p", mdp4_crtc->name, file);
        complete_flip(crtc, file);
 }
 
@@ -717,35 +622,6 @@ void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer)
        mdp4_write(mdp4_kms, REG_MDP4_DISP_INTF_SEL, intf_sel);
 }
 
-static void set_attach(struct drm_crtc *crtc, enum mdp4_pipe pipe_id,
-               struct drm_plane *plane)
-{
-       struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-
-       BUG_ON(pipe_id >= ARRAY_SIZE(mdp4_crtc->planes));
-
-       if (mdp4_crtc->planes[pipe_id] == plane)
-               return;
-
-       mdp4_crtc->planes[pipe_id] = plane;
-       blend_setup(crtc);
-       if (mdp4_crtc->enabled && (plane != mdp4_crtc->plane))
-               crtc_flush(crtc);
-}
-
-void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane)
-{
-       set_attach(crtc, mdp4_plane_pipe(plane), plane);
-}
-
-void mdp4_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane)
-{
-       /* don't actually detatch our primary plane: */
-       if (to_mdp4_crtc(crtc)->plane == plane)
-               return;
-       set_attach(crtc, mdp4_plane_pipe(plane), NULL);
-}
-
 static const char *dma_names[] = {
                "DMA_P", "DMA_S", "DMA_E",
 };
@@ -757,17 +633,13 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
 {
        struct drm_crtc *crtc = NULL;
        struct mdp4_crtc *mdp4_crtc;
-       int ret;
 
        mdp4_crtc = kzalloc(sizeof(*mdp4_crtc), GFP_KERNEL);
-       if (!mdp4_crtc) {
-               ret = -ENOMEM;
-               goto fail;
-       }
+       if (!mdp4_crtc)
+               return ERR_PTR(-ENOMEM);
 
        crtc = &mdp4_crtc->base;
 
-       mdp4_crtc->plane = plane;
        mdp4_crtc->id = id;
 
        mdp4_crtc->ovlp = ovlp_id;
@@ -784,26 +656,14 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
 
        spin_lock_init(&mdp4_crtc->cursor.lock);
 
-       ret = drm_flip_work_init(&mdp4_crtc->unref_fb_work, 16,
-                       "unref fb", unref_fb_worker);
-       if (ret)
-               goto fail;
-
-       ret = drm_flip_work_init(&mdp4_crtc->unref_cursor_work, 64,
+       drm_flip_work_init(&mdp4_crtc->unref_cursor_work,
                        "unref cursor", unref_cursor_worker);
 
-       INIT_FENCE_CB(&mdp4_crtc->pageflip_cb, pageflip_cb);
-
        drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp4_crtc_funcs);
        drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs);
+       plane->crtc = crtc;
 
-       mdp4_plane_install_properties(mdp4_crtc->plane, &crtc->base);
+       mdp4_plane_install_properties(plane, &crtc->base);
 
        return crtc;
-
-fail:
-       if (crtc)
-               mdp4_crtc_destroy(crtc);
-
-       return ERR_PTR(ret);
 }
index 79d804e61cc44e48710f7a4703f38008e7a37b6c..a62109e4ae0d3603822fdf91fe99523f58c7b6e4 100644 (file)
@@ -228,7 +228,6 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
        struct drm_encoder *encoder;
        struct drm_connector *connector;
        struct drm_panel *panel;
-       struct hdmi *hdmi;
        int ret;
 
        /* construct non-private planes: */
@@ -326,11 +325,13 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
        priv->crtcs[priv->num_crtcs++] = crtc;
        priv->encoders[priv->num_encoders++] = encoder;
 
-       hdmi = hdmi_init(dev, encoder);
-       if (IS_ERR(hdmi)) {
-               ret = PTR_ERR(hdmi);
-               dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
-               goto fail;
+       if (priv->hdmi) {
+               /* Construct bridge/connector for HDMI: */
+               ret = hdmi_modeset_init(priv->hdmi, dev, encoder);
+               if (ret) {
+                       dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
+                       goto fail;
+               }
        }
 
        return 0;
@@ -381,6 +382,10 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
        if (IS_ERR(mdp4_kms->dsi_pll_vddio))
                mdp4_kms->dsi_pll_vddio = NULL;
 
+       /* NOTE: driver for this regulator still missing upstream.. use
+        * _get_exclusive() and ignore the error if it does not exist
+        * (and hope that the bootloader left it on for us)
+        */
        mdp4_kms->vdd = devm_regulator_get_exclusive(&pdev->dev, "vdd");
        if (IS_ERR(mdp4_kms->vdd))
                mdp4_kms->vdd = NULL;
index 9ff6e7ccfe90d248fc70a2ccaabba6d92d7aab0a..cbd77bc626d5e8eecce7ec0b8e95797f867a5bf0 100644 (file)
@@ -32,13 +32,6 @@ struct mdp4_kms {
 
        int rev;
 
-       /* Shadow value for MDP4_LAYERMIXER_IN_CFG.. since setup for all
-        * crtcs/encoders is in one shared register, we need to update it
-        * via read/modify/write.  But to avoid getting confused by power-
-        * on-default values after resume, use this shadow value instead:
-        */
-       uint32_t mixer_cfg;
-
        /* mapper-id used to request GEM buffer mapped for scanout: */
        int id;
 
@@ -194,14 +187,6 @@ uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *pixel_formats,
 
 void mdp4_plane_install_properties(struct drm_plane *plane,
                struct drm_mode_object *obj);
-void mdp4_plane_set_scanout(struct drm_plane *plane,
-               struct drm_framebuffer *fb);
-int mdp4_plane_mode_set(struct drm_plane *plane,
-               struct drm_crtc *crtc, struct drm_framebuffer *fb,
-               int crtc_x, int crtc_y,
-               unsigned int crtc_w, unsigned int crtc_h,
-               uint32_t src_x, uint32_t src_y,
-               uint32_t src_w, uint32_t src_h);
 enum mdp4_pipe mdp4_plane_pipe(struct drm_plane *plane);
 struct drm_plane *mdp4_plane_init(struct drm_device *dev,
                enum mdp4_pipe pipe_id, bool private_plane);
@@ -210,8 +195,6 @@ uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc);
 void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file);
 void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config);
 void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer);
-void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane);
-void mdp4_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane);
 struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
                struct drm_plane *plane, int id, int ovlp_id,
                enum mdp4_dma dma_id);
index 310034688c15a60a2a2d2d1364a1fb83bce8375b..4ddc28e1275b381fbc877dc2c706cb4215252b52 100644 (file)
@@ -98,6 +98,9 @@ static const struct drm_connector_funcs mdp4_lvds_connector_funcs = {
        .detect = mdp4_lvds_connector_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .destroy = mdp4_lvds_connector_destroy,
+       .reset = drm_atomic_helper_connector_reset,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 static const struct drm_connector_helper_funcs mdp4_lvds_connector_helper_funcs = {
index 66f33dba1ebb3e520f3a2bfa1e4473eaeaacd7ba..1e5ebe83647d1aa3f86dd2c60024304932c9e11f 100644 (file)
@@ -31,47 +31,26 @@ struct mdp4_plane {
 };
 #define to_mdp4_plane(x) container_of(x, struct mdp4_plane, base)
 
-static struct mdp4_kms *get_kms(struct drm_plane *plane)
-{
-       struct msm_drm_private *priv = plane->dev->dev_private;
-       return to_mdp4_kms(to_mdp_kms(priv->kms));
-}
-
-static int mdp4_plane_update(struct drm_plane *plane,
+static void mdp4_plane_set_scanout(struct drm_plane *plane,
+               struct drm_framebuffer *fb);
+static int mdp4_plane_mode_set(struct drm_plane *plane,
                struct drm_crtc *crtc, struct drm_framebuffer *fb,
                int crtc_x, int crtc_y,
                unsigned int crtc_w, unsigned int crtc_h,
                uint32_t src_x, uint32_t src_y,
-               uint32_t src_w, uint32_t src_h)
-{
-       struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
-
-       mdp4_plane->enabled = true;
-
-       if (plane->fb)
-               drm_framebuffer_unreference(plane->fb);
-
-       drm_framebuffer_reference(fb);
-
-       return mdp4_plane_mode_set(plane, crtc, fb,
-                       crtc_x, crtc_y, crtc_w, crtc_h,
-                       src_x, src_y, src_w, src_h);
-}
+               uint32_t src_w, uint32_t src_h);
 
-static int mdp4_plane_disable(struct drm_plane *plane)
+static struct mdp4_kms *get_kms(struct drm_plane *plane)
 {
-       struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
-       DBG("%s: disable", mdp4_plane->name);
-       if (plane->crtc)
-               mdp4_crtc_detach(plane->crtc, plane);
-       return 0;
+       struct msm_drm_private *priv = plane->dev->dev_private;
+       return to_mdp4_kms(to_mdp_kms(priv->kms));
 }
 
 static void mdp4_plane_destroy(struct drm_plane *plane)
 {
        struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
 
-       mdp4_plane_disable(plane);
+       drm_plane_helper_disable(plane);
        drm_plane_cleanup(plane);
 
        kfree(mdp4_plane);
@@ -92,19 +71,75 @@ int mdp4_plane_set_property(struct drm_plane *plane,
 }
 
 static const struct drm_plane_funcs mdp4_plane_funcs = {
-               .update_plane = mdp4_plane_update,
-               .disable_plane = mdp4_plane_disable,
+               .update_plane = drm_atomic_helper_update_plane,
+               .disable_plane = drm_atomic_helper_disable_plane,
                .destroy = mdp4_plane_destroy,
                .set_property = mdp4_plane_set_property,
+               .reset = drm_atomic_helper_plane_reset,
+               .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+               .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
 };
 
-void mdp4_plane_set_scanout(struct drm_plane *plane,
+static int mdp4_plane_prepare_fb(struct drm_plane *plane,
+               struct drm_framebuffer *fb)
+{
+       struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
+       struct mdp4_kms *mdp4_kms = get_kms(plane);
+
+       DBG("%s: prepare: FB[%u]", mdp4_plane->name, fb->base.id);
+       return msm_framebuffer_prepare(fb, mdp4_kms->id);
+}
+
+static void mdp4_plane_cleanup_fb(struct drm_plane *plane,
+               struct drm_framebuffer *fb)
+{
+       struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
+       struct mdp4_kms *mdp4_kms = get_kms(plane);
+
+       DBG("%s: cleanup: FB[%u]", mdp4_plane->name, fb->base.id);
+       msm_framebuffer_cleanup(fb, mdp4_kms->id);
+}
+
+
+static int mdp4_plane_atomic_check(struct drm_plane *plane,
+               struct drm_plane_state *state)
+{
+       return 0;
+}
+
+static void mdp4_plane_atomic_update(struct drm_plane *plane,
+                                    struct drm_plane_state *old_state)
+{
+       struct drm_plane_state *state = plane->state;
+       int ret;
+
+       ret = mdp4_plane_mode_set(plane,
+                       state->crtc, state->fb,
+                       state->crtc_x, state->crtc_y,
+                       state->crtc_w, state->crtc_h,
+                       state->src_x,  state->src_y,
+                       state->src_w, state->src_h);
+       /* atomic_check should have ensured that this doesn't fail */
+       WARN_ON(ret < 0);
+}
+
+static const struct drm_plane_helper_funcs mdp4_plane_helper_funcs = {
+               .prepare_fb = mdp4_plane_prepare_fb,
+               .cleanup_fb = mdp4_plane_cleanup_fb,
+               .atomic_check = mdp4_plane_atomic_check,
+               .atomic_update = mdp4_plane_atomic_update,
+};
+
+static void mdp4_plane_set_scanout(struct drm_plane *plane,
                struct drm_framebuffer *fb)
 {
        struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
        struct mdp4_kms *mdp4_kms = get_kms(plane);
        enum mdp4_pipe pipe = mdp4_plane->pipe;
-       uint32_t iova;
+       uint32_t iova = msm_framebuffer_iova(fb, mdp4_kms->id, 0);
+
+       DBG("%s: set_scanout: %08x (%u)", mdp4_plane->name,
+                       iova, fb->pitches[0]);
 
        mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_STRIDE_A(pipe),
                        MDP4_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) |
@@ -114,7 +149,6 @@ void mdp4_plane_set_scanout(struct drm_plane *plane,
                        MDP4_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) |
                        MDP4_PIPE_SRC_STRIDE_B_P3(fb->pitches[3]));
 
-       msm_gem_get_iova(msm_framebuffer_bo(fb, 0), mdp4_kms->id, &iova);
        mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP0_BASE(pipe), iova);
 
        plane->fb = fb;
@@ -122,7 +156,7 @@ void mdp4_plane_set_scanout(struct drm_plane *plane,
 
 #define MDP4_VG_PHASE_STEP_DEFAULT     0x20000000
 
-int mdp4_plane_mode_set(struct drm_plane *plane,
+static int mdp4_plane_mode_set(struct drm_plane *plane,
                struct drm_crtc *crtc, struct drm_framebuffer *fb,
                int crtc_x, int crtc_y,
                unsigned int crtc_w, unsigned int crtc_h,
@@ -137,6 +171,11 @@ int mdp4_plane_mode_set(struct drm_plane *plane,
        uint32_t phasex_step = MDP4_VG_PHASE_STEP_DEFAULT;
        uint32_t phasey_step = MDP4_VG_PHASE_STEP_DEFAULT;
 
+       if (!(crtc && fb)) {
+               DBG("%s: disabled!", mdp4_plane->name);
+               return 0;
+       }
+
        /* src values are in Q16 fixed point, convert to integer: */
        src_x = src_x >> 16;
        src_y = src_y >> 16;
@@ -197,9 +236,6 @@ int mdp4_plane_mode_set(struct drm_plane *plane,
        mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEX_STEP(pipe), phasex_step);
        mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEY_STEP(pipe), phasey_step);
 
-       /* TODO detach from old crtc (if we had more than one) */
-       mdp4_crtc_attach(crtc, plane);
-
        return 0;
 }
 
@@ -239,9 +275,12 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev,
                        ARRAY_SIZE(mdp4_plane->formats));
 
        type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
-       drm_universal_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,
-                                mdp4_plane->formats, mdp4_plane->nformats,
-                                type);
+       ret = drm_universal_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,
+                                mdp4_plane->formats, mdp4_plane->nformats, type);
+       if (ret)
+               goto fail;
+
+       drm_plane_helper_add(plane, &mdp4_plane_helper_funcs);
 
        mdp4_plane_install_properties(plane, &plane->base);
 
index 67f4f896ba8ce99647812f28e44b54e18ec0d4ee..e87ef5512cb0ade999f44d7c2169069d7022cdc6 100644 (file)
@@ -10,14 +10,14 @@ git clone https://github.com/freedreno/envytools.git
 The rules-ng-ng source files this header was generated from are:
 - /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    647 bytes, from 2013-11-30 14:45:35)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  17996 bytes, from 2013-12-01 19:10:31)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2013-11-30 15:00:52)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-06-25 12:55:02)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20136 bytes, from 2014-10-31 16:51:39)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1940 bytes, from 2014-10-31 16:51:39)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  23963 bytes, from 2014-10-31 16:51:46)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-06-25 12:53:44)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
 
 Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c
new file mode 100644 (file)
index 0000000..b0a4431
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2014 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 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 "mdp5_kms.h"
+#include "mdp5_cfg.h"
+
+struct mdp5_cfg_handler {
+       int revision;
+       struct mdp5_cfg config;
+};
+
+/* mdp5_cfg must be exposed (used in mdp5.xml.h) */
+const struct mdp5_cfg_hw *mdp5_cfg = NULL;
+
+const struct mdp5_cfg_hw msm8x74_config = {
+       .name = "msm8x74",
+       .smp = {
+               .mmb_count = 22,
+               .mmb_size = 4096,
+       },
+       .ctl = {
+               .count = 5,
+               .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 },
+       },
+       .pipe_vig = {
+               .count = 3,
+               .base = { 0x01200, 0x01600, 0x01a00 },
+       },
+       .pipe_rgb = {
+               .count = 3,
+               .base = { 0x01e00, 0x02200, 0x02600 },
+       },
+       .pipe_dma = {
+               .count = 2,
+               .base = { 0x02a00, 0x02e00 },
+       },
+       .lm = {
+               .count = 5,
+               .base = { 0x03200, 0x03600, 0x03a00, 0x03e00, 0x04200 },
+               .nb_stages = 5,
+       },
+       .dspp = {
+               .count = 3,
+               .base = { 0x04600, 0x04a00, 0x04e00 },
+       },
+       .ad = {
+               .count = 2,
+               .base = { 0x13100, 0x13300 }, /* NOTE: no ad in v1.0 */
+       },
+       .intf = {
+               .count = 4,
+               .base = { 0x12500, 0x12700, 0x12900, 0x12b00 },
+       },
+       .max_clk = 200000000,
+};
+
+const struct mdp5_cfg_hw apq8084_config = {
+       .name = "apq8084",
+       .smp = {
+               .mmb_count = 44,
+               .mmb_size = 8192,
+               .reserved_state[0] = GENMASK(7, 0),     /* first 8 MMBs */
+               .reserved[CID_RGB0] = 2,
+               .reserved[CID_RGB1] = 2,
+               .reserved[CID_RGB2] = 2,
+               .reserved[CID_RGB3] = 2,
+       },
+       .ctl = {
+               .count = 5,
+               .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 },
+       },
+       .pipe_vig = {
+               .count = 4,
+               .base = { 0x01200, 0x01600, 0x01a00, 0x01e00 },
+       },
+       .pipe_rgb = {
+               .count = 4,
+               .base = { 0x02200, 0x02600, 0x02a00, 0x02e00 },
+       },
+       .pipe_dma = {
+               .count = 2,
+               .base = { 0x03200, 0x03600 },
+       },
+       .lm = {
+               .count = 6,
+               .base = { 0x03a00, 0x03e00, 0x04200, 0x04600, 0x04a00, 0x04e00 },
+               .nb_stages = 5,
+       },
+       .dspp = {
+               .count = 4,
+               .base = { 0x05200, 0x05600, 0x05a00, 0x05e00 },
+
+       },
+       .ad = {
+               .count = 3,
+               .base = { 0x13500, 0x13700, 0x13900 },
+       },
+       .intf = {
+               .count = 5,
+               .base = { 0x12500, 0x12700, 0x12900, 0x12b00, 0x12d00 },
+       },
+       .max_clk = 320000000,
+};
+
+static const struct mdp5_cfg_handler cfg_handlers[] = {
+       { .revision = 0, .config = { .hw = &msm8x74_config } },
+       { .revision = 2, .config = { .hw = &msm8x74_config } },
+       { .revision = 3, .config = { .hw = &apq8084_config } },
+};
+
+
+static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev);
+
+const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_handler)
+{
+       return cfg_handler->config.hw;
+}
+
+struct mdp5_cfg *mdp5_cfg_get_config(struct mdp5_cfg_handler *cfg_handler)
+{
+       return &cfg_handler->config;
+}
+
+int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_handler)
+{
+       return cfg_handler->revision;
+}
+
+void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_handler)
+{
+       kfree(cfg_handler);
+}
+
+struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
+               uint32_t major, uint32_t minor)
+{
+       struct drm_device *dev = mdp5_kms->dev;
+       struct platform_device *pdev = dev->platformdev;
+       struct mdp5_cfg_handler *cfg_handler;
+       struct mdp5_cfg_platform *pconfig;
+       int i, ret = 0;
+
+       cfg_handler = kzalloc(sizeof(*cfg_handler), GFP_KERNEL);
+       if (unlikely(!cfg_handler)) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       if (major != 1) {
+               dev_err(dev->dev, "unexpected MDP major version: v%d.%d\n",
+                               major, minor);
+               ret = -ENXIO;
+               goto fail;
+       }
+
+       /* only after mdp5_cfg global pointer's init can we access the hw */
+       for (i = 0; i < ARRAY_SIZE(cfg_handlers); i++) {
+               if (cfg_handlers[i].revision != minor)
+                       continue;
+               mdp5_cfg = cfg_handlers[i].config.hw;
+
+               break;
+       }
+       if (unlikely(!mdp5_cfg)) {
+               dev_err(dev->dev, "unexpected MDP minor revision: v%d.%d\n",
+                               major, minor);
+               ret = -ENXIO;
+               goto fail;
+       }
+
+       cfg_handler->revision = minor;
+       cfg_handler->config.hw = mdp5_cfg;
+
+       pconfig = mdp5_get_config(pdev);
+       memcpy(&cfg_handler->config.platform, pconfig, sizeof(*pconfig));
+
+       DBG("MDP5: %s hw config selected", mdp5_cfg->name);
+
+       return cfg_handler;
+
+fail:
+       if (cfg_handler)
+               mdp5_cfg_destroy(cfg_handler);
+
+       return NULL;
+}
+
+static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev)
+{
+       static struct mdp5_cfg_platform config = {};
+#ifdef CONFIG_OF
+       /* TODO */
+#endif
+       config.iommu = iommu_domain_alloc(&platform_bus_type);
+
+       return &config;
+}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h
new file mode 100644 (file)
index 0000000..dba4d52
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2014 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 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.
+ */
+
+#ifndef __MDP5_CFG_H__
+#define __MDP5_CFG_H__
+
+#include "msm_drv.h"
+
+/*
+ * mdp5_cfg
+ *
+ * This module configures the dynamic offsets used by mdp5.xml.h
+ * (initialized in mdp5_cfg.c)
+ */
+extern const struct mdp5_cfg_hw *mdp5_cfg;
+
+#define MAX_CTL                        8
+#define MAX_BASES              8
+#define MAX_SMP_BLOCKS         44
+#define MAX_CLIENTS            32
+
+typedef DECLARE_BITMAP(mdp5_smp_state_t, MAX_SMP_BLOCKS);
+
+#define MDP5_SUB_BLOCK_DEFINITION \
+       int count; \
+       uint32_t base[MAX_BASES]
+
+struct mdp5_sub_block {
+       MDP5_SUB_BLOCK_DEFINITION;
+};
+
+struct mdp5_lm_block {
+       MDP5_SUB_BLOCK_DEFINITION;
+       uint32_t nb_stages;             /* number of stages per blender */
+};
+
+struct mdp5_smp_block {
+       int mmb_count;                  /* number of SMP MMBs */
+       int mmb_size;                   /* MMB: size in bytes */
+       mdp5_smp_state_t reserved_state;/* SMP MMBs statically allocated */
+       int reserved[MAX_CLIENTS];      /* # of MMBs allocated per client */
+};
+
+struct mdp5_cfg_hw {
+       char  *name;
+
+       struct mdp5_smp_block smp;
+       struct mdp5_sub_block ctl;
+       struct mdp5_sub_block pipe_vig;
+       struct mdp5_sub_block pipe_rgb;
+       struct mdp5_sub_block pipe_dma;
+       struct mdp5_lm_block  lm;
+       struct mdp5_sub_block dspp;
+       struct mdp5_sub_block ad;
+       struct mdp5_sub_block intf;
+
+       uint32_t max_clk;
+};
+
+/* platform config data (ie. from DT, or pdata) */
+struct mdp5_cfg_platform {
+       struct iommu_domain *iommu;
+};
+
+struct mdp5_cfg {
+       const struct mdp5_cfg_hw *hw;
+       struct mdp5_cfg_platform platform;
+};
+
+struct mdp5_kms;
+struct mdp5_cfg_handler;
+
+const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_hnd);
+struct mdp5_cfg *mdp5_cfg_get_config(struct mdp5_cfg_handler *cfg_hnd);
+int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_hnd);
+
+struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
+               uint32_t major, uint32_t minor);
+void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_hnd);
+
+#endif /* __MDP5_CFG_H__ */
index ebe2e60f3ab1147826e49a79b9772f4115635040..0e9a2e3a82d76e1e104fd1e136d8924755706586 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2014 The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
 
 #include "mdp5_kms.h"
 
+#include <linux/sort.h>
 #include <drm/drm_mode.h>
 #include "drm_crtc.h"
 #include "drm_crtc_helper.h"
 #include "drm_flip_work.h"
 
+#define SSPP_MAX       (SSPP_RGB3 + 1) /* TODO: Add SSPP_MAX in mdp5.xml.h */
+
 struct mdp5_crtc {
        struct drm_crtc base;
        char name[8];
-       struct drm_plane *plane;
-       struct drm_plane *planes[8];
        int id;
        bool enabled;
 
-       /* which mixer/encoder we route output to: */
-       int mixer;
+       /* layer mixer used for this CRTC (+ its lock): */
+#define GET_LM_ID(crtc_id)     ((crtc_id == 3) ? 5 : crtc_id)
+       int lm;
+       spinlock_t lm_lock;     /* protect REG_MDP5_LM_* registers */
+
+       /* CTL used for this CRTC: */
+       struct mdp5_ctl *ctl;
 
        /* if there is a pending flip, these will be non-null: */
        struct drm_pending_vblank_event *event;
-       struct msm_fence_cb pageflip_cb;
 
 #define PENDING_CURSOR 0x1
 #define PENDING_FLIP   0x2
        atomic_t pending;
 
-       /* the fb that we logically (from PoV of KMS API) hold a ref
-        * to.  Which we may not yet be scanning out (we may still
-        * be scanning out previous in case of page_flip while waiting
-        * for gpu rendering to complete:
-        */
-       struct drm_framebuffer *fb;
-
-       /* the fb that we currently hold a scanout ref to: */
-       struct drm_framebuffer *scanout_fb;
-
-       /* for unref'ing framebuffers after scanout completes: */
-       struct drm_flip_work unref_fb_work;
-
        struct mdp_irq vblank;
        struct mdp_irq err;
 };
@@ -73,67 +66,38 @@ static void request_pending(struct drm_crtc *crtc, uint32_t pending)
        mdp_irq_register(&get_kms(crtc)->base, &mdp5_crtc->vblank);
 }
 
-static void crtc_flush(struct drm_crtc *crtc)
-{
-       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-       struct mdp5_kms *mdp5_kms = get_kms(crtc);
-       int id = mdp5_crtc->id;
-       uint32_t i, flush = 0;
-
-       for (i = 0; i < ARRAY_SIZE(mdp5_crtc->planes); i++) {
-               struct drm_plane *plane = mdp5_crtc->planes[i];
-               if (plane) {
-                       enum mdp5_pipe pipe = mdp5_plane_pipe(plane);
-                       flush |= pipe2flush(pipe);
-               }
-       }
-       flush |= mixer2flush(mdp5_crtc->id);
-       flush |= MDP5_CTL_FLUSH_CTL;
-
-       DBG("%s: flush=%08x", mdp5_crtc->name, flush);
-
-       mdp5_write(mdp5_kms, REG_MDP5_CTL_FLUSH(id), flush);
-}
+#define mdp5_lm_get_flush(lm)  mdp_ctl_flush_mask_lm(lm)
 
-static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb)
+static void crtc_flush(struct drm_crtc *crtc, u32 flush_mask)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-       struct drm_framebuffer *old_fb = mdp5_crtc->fb;
-
-       /* grab reference to incoming scanout fb: */
-       drm_framebuffer_reference(new_fb);
-       mdp5_crtc->base.primary->fb = new_fb;
-       mdp5_crtc->fb = new_fb;
 
-       if (old_fb)
-               drm_flip_work_queue(&mdp5_crtc->unref_fb_work, old_fb);
+       DBG("%s: flush=%08x", mdp5_crtc->name, flush_mask);
+       mdp5_ctl_commit(mdp5_crtc->ctl, flush_mask);
 }
 
-/* unlike update_fb(), take a ref to the new scanout fb *before* updating
- * plane, then call this.  Needed to ensure we don't unref the buffer that
- * is actually still being scanned out.
- *
- * Note that this whole thing goes away with atomic.. since we can defer
- * calling into driver until rendering is done.
+/*
+ * flush updates, to make sure hw is updated to new scanout fb,
+ * so that we can safely queue unref to current fb (ie. next
+ * vblank we know hw is done w/ previous scanout_fb).
  */
-static void update_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb)
+static void crtc_flush_all(struct drm_crtc *crtc)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       struct drm_plane *plane;
+       uint32_t flush_mask = 0;
 
-       /* flush updates, to make sure hw is updated to new scanout fb,
-        * so that we can safely queue unref to current fb (ie. next
-        * vblank we know hw is done w/ previous scanout_fb).
-        */
-       crtc_flush(crtc);
-
-       if (mdp5_crtc->scanout_fb)
-               drm_flip_work_queue(&mdp5_crtc->unref_fb_work,
-                               mdp5_crtc->scanout_fb);
+       /* we could have already released CTL in the disable path: */
+       if (!mdp5_crtc->ctl)
+               return;
 
-       mdp5_crtc->scanout_fb = fb;
+       drm_atomic_crtc_for_each_plane(plane, crtc) {
+               flush_mask |= mdp5_plane_get_flush(plane);
+       }
+       flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl);
+       flush_mask |= mdp5_lm_get_flush(mdp5_crtc->lm);
 
-       /* enable vblank to complete flip: */
-       request_pending(crtc, PENDING_FLIP);
+       crtc_flush(crtc, flush_mask);
 }
 
 /* if file!=NULL, this is preclose potential cancel-flip path */
@@ -142,7 +106,8 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct drm_pending_vblank_event *event;
-       unsigned long flags, i;
+       struct drm_plane *plane;
+       unsigned long flags;
 
        spin_lock_irqsave(&dev->event_lock, flags);
        event = mdp5_crtc->event;
@@ -153,50 +118,22 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
                 */
                if (!file || (event->base.file_priv == file)) {
                        mdp5_crtc->event = NULL;
+                       DBG("%s: send event: %p", mdp5_crtc->name, event);
                        drm_send_vblank_event(dev, mdp5_crtc->id, event);
                }
        }
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
-       for (i = 0; i < ARRAY_SIZE(mdp5_crtc->planes); i++) {
-               struct drm_plane *plane = mdp5_crtc->planes[i];
-               if (plane)
-                       mdp5_plane_complete_flip(plane);
+       drm_atomic_crtc_for_each_plane(plane, crtc) {
+               mdp5_plane_complete_flip(plane);
        }
 }
 
-static void pageflip_cb(struct msm_fence_cb *cb)
-{
-       struct mdp5_crtc *mdp5_crtc =
-               container_of(cb, struct mdp5_crtc, pageflip_cb);
-       struct drm_crtc *crtc = &mdp5_crtc->base;
-       struct drm_framebuffer *fb = mdp5_crtc->fb;
-
-       if (!fb)
-               return;
-
-       drm_framebuffer_reference(fb);
-       mdp5_plane_set_scanout(mdp5_crtc->plane, fb);
-       update_scanout(crtc, fb);
-}
-
-static void unref_fb_worker(struct drm_flip_work *work, void *val)
-{
-       struct mdp5_crtc *mdp5_crtc =
-               container_of(work, struct mdp5_crtc, unref_fb_work);
-       struct drm_device *dev = mdp5_crtc->base.dev;
-
-       mutex_lock(&dev->mode_config.mutex);
-       drm_framebuffer_unreference(val);
-       mutex_unlock(&dev->mode_config.mutex);
-}
-
 static void mdp5_crtc_destroy(struct drm_crtc *crtc)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
 
        drm_crtc_cleanup(crtc);
-       drm_flip_work_cleanup(&mdp5_crtc->unref_fb_work);
 
        kfree(mdp5_crtc);
 }
@@ -214,6 +151,8 @@ static void mdp5_crtc_dpms(struct drm_crtc *crtc, int mode)
                        mdp5_enable(mdp5_kms);
                        mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err);
                } else {
+                       /* set STAGE_UNUSED for all layers */
+                       mdp5_ctl_blend(mdp5_crtc->ctl, mdp5_crtc->lm, 0x00000000);
                        mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err);
                        mdp5_disable(mdp5_kms);
                }
@@ -228,54 +167,78 @@ static bool mdp5_crtc_mode_fixup(struct drm_crtc *crtc,
        return true;
 }
 
+/*
+ * blend_setup() - blend all the planes of a CRTC
+ *
+ * When border is enabled, the border color will ALWAYS be the base layer.
+ * Therefore, the first plane (private RGB pipe) will start at STAGE0.
+ * If disabled, the first plane starts at STAGE_BASE.
+ *
+ * Note:
+ * Border is not enabled here because the private plane is exactly
+ * the CRTC resolution.
+ */
 static void blend_setup(struct drm_crtc *crtc)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
        struct mdp5_kms *mdp5_kms = get_kms(crtc);
-       int id = mdp5_crtc->id;
+       struct drm_plane *plane;
+       const struct mdp5_cfg_hw *hw_cfg;
+       uint32_t lm = mdp5_crtc->lm, blend_cfg = 0;
+       unsigned long flags;
+#define blender(stage) ((stage) - STAGE_BASE)
 
-       /*
-        * Hard-coded setup for now until I figure out how the
-        * layer-mixer works
-        */
+       hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
 
-       /* LM[id]: */
-       mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(id),
-                       MDP5_LM_BLEND_COLOR_OUT_STAGE0_FG_ALPHA);
-       mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_OP_MODE(id, 0),
-                       MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) |
-                       MDP5_LM_BLEND_OP_MODE_BG_ALPHA(FG_PIXEL) |
-                       MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA);
-       mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(id, 0), 0xff);
-       mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(id, 0), 0x00);
-
-       /* NOTE: seems that LM[n] and CTL[m], we do not need n==m.. but
-        * we want to be setting CTL[m].LAYER[n].  Not sure what the
-        * point of having CTL[m].LAYER[o] (for o!=n).. maybe that is
-        * used when chaining up mixers for high resolution displays?
-        */
+       spin_lock_irqsave(&mdp5_crtc->lm_lock, flags);
+
+       /* ctl could be released already when we are shutting down: */
+       if (!mdp5_crtc->ctl)
+               goto out;
 
-       /* CTL[id]: */
-       mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 0),
-                       MDP5_CTL_LAYER_REG_RGB0(STAGE0) |
-                       MDP5_CTL_LAYER_REG_BORDER_COLOR);
-       mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 1), 0);
-       mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 2), 0);
-       mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 3), 0);
-       mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 4), 0);
+       drm_atomic_crtc_for_each_plane(plane, crtc) {
+               enum mdp_mixer_stage_id stage =
+                       to_mdp5_plane_state(plane->state)->stage;
+
+               /*
+                * Note: This cannot happen with current implementation but
+                * we need to check this condition once z property is added
+                */
+               BUG_ON(stage > hw_cfg->lm.nb_stages);
+
+               /* LM */
+               mdp5_write(mdp5_kms,
+                               REG_MDP5_LM_BLEND_OP_MODE(lm, blender(stage)),
+                               MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) |
+                               MDP5_LM_BLEND_OP_MODE_BG_ALPHA(BG_CONST));
+               mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(lm,
+                               blender(stage)), 0xff);
+               mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(lm,
+                               blender(stage)), 0x00);
+               /* CTL */
+               blend_cfg |= mdp_ctl_blend_mask(mdp5_plane_pipe(plane), stage);
+               DBG("%s: blending pipe %s on stage=%d", mdp5_crtc->name,
+                               pipe2name(mdp5_plane_pipe(plane)), stage);
+       }
+
+       DBG("%s: lm%d: blend config = 0x%08x", mdp5_crtc->name, lm, blend_cfg);
+       mdp5_ctl_blend(mdp5_crtc->ctl, lm, blend_cfg);
+
+out:
+       spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags);
 }
 
-static int mdp5_crtc_mode_set(struct drm_crtc *crtc,
-               struct drm_display_mode *mode,
-               struct drm_display_mode *adjusted_mode,
-               int x, int y,
-               struct drm_framebuffer *old_fb)
+static void mdp5_crtc_mode_set_nofb(struct drm_crtc *crtc)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
        struct mdp5_kms *mdp5_kms = get_kms(crtc);
-       int ret;
+       unsigned long flags;
+       struct drm_display_mode *mode;
 
-       mode = adjusted_mode;
+       if (WARN_ON(!crtc->state))
+               return;
+
+       mode = &crtc->state->adjusted_mode;
 
        DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
                        mdp5_crtc->name, mode->base.id, mode->name,
@@ -286,28 +249,11 @@ static int mdp5_crtc_mode_set(struct drm_crtc *crtc,
                        mode->vsync_end, mode->vtotal,
                        mode->type, mode->flags);
 
-       /* grab extra ref for update_scanout() */
-       drm_framebuffer_reference(crtc->primary->fb);
-
-       ret = mdp5_plane_mode_set(mdp5_crtc->plane, crtc, crtc->primary->fb,
-                       0, 0, mode->hdisplay, mode->vdisplay,
-                       x << 16, y << 16,
-                       mode->hdisplay << 16, mode->vdisplay << 16);
-       if (ret) {
-               drm_framebuffer_unreference(crtc->primary->fb);
-               dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
-                               mdp5_crtc->name, ret);
-               return ret;
-       }
-
-       mdp5_write(mdp5_kms, REG_MDP5_LM_OUT_SIZE(mdp5_crtc->id),
+       spin_lock_irqsave(&mdp5_crtc->lm_lock, flags);
+       mdp5_write(mdp5_kms, REG_MDP5_LM_OUT_SIZE(mdp5_crtc->lm),
                        MDP5_LM_OUT_SIZE_WIDTH(mode->hdisplay) |
                        MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay));
-
-       update_fb(crtc, crtc->primary->fb);
-       update_scanout(crtc, crtc->primary->fb);
-
-       return 0;
+       spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags);
 }
 
 static void mdp5_crtc_prepare(struct drm_crtc *crtc)
@@ -321,66 +267,119 @@ static void mdp5_crtc_prepare(struct drm_crtc *crtc)
 
 static void mdp5_crtc_commit(struct drm_crtc *crtc)
 {
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       DBG("%s", mdp5_crtc->name);
        mdp5_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
-       crtc_flush(crtc);
+       crtc_flush_all(crtc);
        /* drop the ref to mdp clk's that we got in prepare: */
        mdp5_disable(get_kms(crtc));
 }
 
-static int mdp5_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
-               struct drm_framebuffer *old_fb)
+static void mdp5_crtc_load_lut(struct drm_crtc *crtc)
+{
+}
+
+struct plane_state {
+       struct drm_plane *plane;
+       struct mdp5_plane_state *state;
+};
+
+static int pstate_cmp(const void *a, const void *b)
+{
+       struct plane_state *pa = (struct plane_state *)a;
+       struct plane_state *pb = (struct plane_state *)b;
+       return pa->state->zpos - pb->state->zpos;
+}
+
+static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
+               struct drm_crtc_state *state)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-       struct drm_plane *plane = mdp5_crtc->plane;
-       struct drm_display_mode *mode = &crtc->mode;
-       int ret;
-
-       /* grab extra ref for update_scanout() */
-       drm_framebuffer_reference(crtc->primary->fb);
-
-       ret = mdp5_plane_mode_set(plane, crtc, crtc->primary->fb,
-                       0, 0, mode->hdisplay, mode->vdisplay,
-                       x << 16, y << 16,
-                       mode->hdisplay << 16, mode->vdisplay << 16);
-       if (ret) {
-               drm_framebuffer_unreference(crtc->primary->fb);
-               return ret;
+       struct mdp5_kms *mdp5_kms = get_kms(crtc);
+       struct drm_plane *plane;
+       struct drm_device *dev = crtc->dev;
+       struct plane_state pstates[STAGE3 + 1];
+       int cnt = 0, i;
+
+       DBG("%s: check", mdp5_crtc->name);
+
+       if (mdp5_crtc->event) {
+               dev_err(dev->dev, "already pending flip!\n");
+               return -EBUSY;
        }
 
-       update_fb(crtc, crtc->primary->fb);
-       update_scanout(crtc, crtc->primary->fb);
+       /* request a free CTL, if none is already allocated for this CRTC */
+       if (state->enable && !mdp5_crtc->ctl) {
+               mdp5_crtc->ctl = mdp5_ctlm_request(mdp5_kms->ctlm, crtc);
+               if (WARN_ON(!mdp5_crtc->ctl))
+                       return -EINVAL;
+       }
+
+       /* verify that there are not too many planes attached to crtc
+        * and that we don't have conflicting mixer stages:
+        */
+       drm_atomic_crtc_state_for_each_plane(plane, state) {
+               struct drm_plane_state *pstate;
+
+               if (cnt >= ARRAY_SIZE(pstates)) {
+                       dev_err(dev->dev, "too many planes!\n");
+                       return -EINVAL;
+               }
+
+               pstate = state->state->plane_states[drm_plane_index(plane)];
+
+               /* plane might not have changed, in which case take
+                * current state:
+                */
+               if (!pstate)
+                       pstate = plane->state;
+
+               pstates[cnt].plane = plane;
+               pstates[cnt].state = to_mdp5_plane_state(pstate);
+
+               cnt++;
+       }
+
+       sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL);
+
+       for (i = 0; i < cnt; i++) {
+               pstates[i].state->stage = STAGE_BASE + i;
+               DBG("%s: assign pipe %s on stage=%d", mdp5_crtc->name,
+                               pipe2name(mdp5_plane_pipe(pstates[i].plane)),
+                               pstates[i].state->stage);
+       }
 
        return 0;
 }
 
-static void mdp5_crtc_load_lut(struct drm_crtc *crtc)
+static void mdp5_crtc_atomic_begin(struct drm_crtc *crtc)
 {
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       DBG("%s: begin", mdp5_crtc->name);
 }
 
-static int mdp5_crtc_page_flip(struct drm_crtc *crtc,
-               struct drm_framebuffer *new_fb,
-               struct drm_pending_vblank_event *event,
-               uint32_t page_flip_flags)
+static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
        struct drm_device *dev = crtc->dev;
-       struct drm_gem_object *obj;
        unsigned long flags;
 
-       if (mdp5_crtc->event) {
-               dev_err(dev->dev, "already pending flip!\n");
-               return -EBUSY;
-       }
+       DBG("%s: flush", mdp5_crtc->name);
 
-       obj = msm_framebuffer_bo(new_fb, 0);
+       WARN_ON(mdp5_crtc->event);
 
        spin_lock_irqsave(&dev->event_lock, flags);
-       mdp5_crtc->event = event;
+       mdp5_crtc->event = crtc->state->event;
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
-       update_fb(crtc, new_fb);
+       blend_setup(crtc);
+       crtc_flush_all(crtc);
+       request_pending(crtc, PENDING_FLIP);
 
-       return msm_gem_queue_inactive_cb(obj, &mdp5_crtc->pageflip_cb);
+       if (mdp5_crtc->ctl && !crtc->state->enable) {
+               mdp5_ctl_release(mdp5_crtc->ctl);
+               mdp5_crtc->ctl = NULL;
+       }
 }
 
 static int mdp5_crtc_set_property(struct drm_crtc *crtc,
@@ -391,27 +390,33 @@ static int mdp5_crtc_set_property(struct drm_crtc *crtc,
 }
 
 static const struct drm_crtc_funcs mdp5_crtc_funcs = {
-       .set_config = drm_crtc_helper_set_config,
+       .set_config = drm_atomic_helper_set_config,
        .destroy = mdp5_crtc_destroy,
-       .page_flip = mdp5_crtc_page_flip,
+       .page_flip = drm_atomic_helper_page_flip,
        .set_property = mdp5_crtc_set_property,
+       .reset = drm_atomic_helper_crtc_reset,
+       .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
 };
 
 static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = {
        .dpms = mdp5_crtc_dpms,
        .mode_fixup = mdp5_crtc_mode_fixup,
-       .mode_set = mdp5_crtc_mode_set,
+       .mode_set_nofb = mdp5_crtc_mode_set_nofb,
+       .mode_set = drm_helper_crtc_mode_set,
+       .mode_set_base = drm_helper_crtc_mode_set_base,
        .prepare = mdp5_crtc_prepare,
        .commit = mdp5_crtc_commit,
-       .mode_set_base = mdp5_crtc_mode_set_base,
        .load_lut = mdp5_crtc_load_lut,
+       .atomic_check = mdp5_crtc_atomic_check,
+       .atomic_begin = mdp5_crtc_atomic_begin,
+       .atomic_flush = mdp5_crtc_atomic_flush,
 };
 
 static void mdp5_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
 {
        struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, vblank);
        struct drm_crtc *crtc = &mdp5_crtc->base;
-       struct msm_drm_private *priv = crtc->dev->dev_private;
        unsigned pending;
 
        mdp_irq_unregister(&get_kms(crtc)->base, &mdp5_crtc->vblank);
@@ -420,16 +425,14 @@ static void mdp5_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
 
        if (pending & PENDING_FLIP) {
                complete_flip(crtc, NULL);
-               drm_flip_work_commit(&mdp5_crtc->unref_fb_work, priv->wq);
        }
 }
 
 static void mdp5_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus)
 {
        struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, err);
-       struct drm_crtc *crtc = &mdp5_crtc->base;
+
        DBG("%s: error: %08x", mdp5_crtc->name, irqstatus);
-       crtc_flush(crtc);
 }
 
 uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc)
@@ -450,10 +453,9 @@ void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf,
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
        struct mdp5_kms *mdp5_kms = get_kms(crtc);
-       static const enum mdp5_intfnum intfnum[] = {
-                       INTF0, INTF1, INTF2, INTF3,
-       };
+       uint32_t flush_mask = 0;
        uint32_t intf_sel;
+       unsigned long flags;
 
        /* now that we know what irq's we want: */
        mdp5_crtc->err.irqmask = intf2err(intf);
@@ -463,6 +465,7 @@ void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf,
        if (!mdp5_kms)
                return;
 
+       spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
        intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL);
 
        switch (intf) {
@@ -487,45 +490,25 @@ void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf,
                break;
        }
 
-       blend_setup(crtc);
+       mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, intf_sel);
+       spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
 
        DBG("%s: intf_sel=%08x", mdp5_crtc->name, intf_sel);
+       mdp5_ctl_set_intf(mdp5_crtc->ctl, intf);
+       flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl);
+       flush_mask |= mdp5_lm_get_flush(mdp5_crtc->lm);
 
-       mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, intf_sel);
-       mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(mdp5_crtc->id),
-                       MDP5_CTL_OP_MODE(MODE_NONE) |
-                       MDP5_CTL_OP_INTF_NUM(intfnum[intf]));
-
-       crtc_flush(crtc);
+       crtc_flush(crtc, flush_mask);
 }
 
-static void set_attach(struct drm_crtc *crtc, enum mdp5_pipe pipe_id,
-               struct drm_plane *plane)
+int mdp5_crtc_get_lm(struct drm_crtc *crtc)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
 
-       BUG_ON(pipe_id >= ARRAY_SIZE(mdp5_crtc->planes));
+       if (WARN_ON(!crtc))
+               return -EINVAL;
 
-       if (mdp5_crtc->planes[pipe_id] == plane)
-               return;
-
-       mdp5_crtc->planes[pipe_id] = plane;
-       blend_setup(crtc);
-       if (mdp5_crtc->enabled && (plane != mdp5_crtc->plane))
-               crtc_flush(crtc);
-}
-
-void mdp5_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane)
-{
-       set_attach(crtc, mdp5_plane_pipe(plane), plane);
-}
-
-void mdp5_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane)
-{
-       /* don't actually detatch our primary plane: */
-       if (to_mdp5_crtc(crtc)->plane == plane)
-               return;
-       set_attach(crtc, mdp5_plane_pipe(plane), NULL);
+       return mdp5_crtc->lm;
 }
 
 /* initialize crtc */
@@ -534,18 +517,17 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
 {
        struct drm_crtc *crtc = NULL;
        struct mdp5_crtc *mdp5_crtc;
-       int ret;
 
        mdp5_crtc = kzalloc(sizeof(*mdp5_crtc), GFP_KERNEL);
-       if (!mdp5_crtc) {
-               ret = -ENOMEM;
-               goto fail;
-       }
+       if (!mdp5_crtc)
+               return ERR_PTR(-ENOMEM);
 
        crtc = &mdp5_crtc->base;
 
-       mdp5_crtc->plane = plane;
        mdp5_crtc->id = id;
+       mdp5_crtc->lm = GET_LM_ID(id);
+
+       spin_lock_init(&mdp5_crtc->lm_lock);
 
        mdp5_crtc->vblank.irq = mdp5_crtc_vblank_irq;
        mdp5_crtc->err.irq = mdp5_crtc_err_irq;
@@ -553,23 +535,11 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
        snprintf(mdp5_crtc->name, sizeof(mdp5_crtc->name), "%s:%d",
                        pipe2name(mdp5_plane_pipe(plane)), id);
 
-       ret = drm_flip_work_init(&mdp5_crtc->unref_fb_work, 16,
-                       "unref fb", unref_fb_worker);
-       if (ret)
-               goto fail;
-
-       INIT_FENCE_CB(&mdp5_crtc->pageflip_cb, pageflip_cb);
-
        drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp5_crtc_funcs);
        drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs);
+       plane->crtc = crtc;
 
-       mdp5_plane_install_properties(mdp5_crtc->plane, &crtc->base);
+       mdp5_plane_install_properties(plane, &crtc->base);
 
        return crtc;
-
-fail:
-       if (crtc)
-               mdp5_crtc_destroy(crtc);
-
-       return ERR_PTR(ret);
 }
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c
new file mode 100644 (file)
index 0000000..dea4505
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2014 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 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 "mdp5_kms.h"
+#include "mdp5_ctl.h"
+
+/*
+ * CTL - MDP Control Pool Manager
+ *
+ * Controls are shared between all CRTCs.
+ *
+ * They are intended to be used for data path configuration.
+ * The top level register programming describes the complete data path for
+ * a specific data path ID - REG_MDP5_CTL_*(<id>, ...)
+ *
+ * Hardware capabilities determine the number of concurrent data paths
+ *
+ * In certain use cases (high-resolution dual pipe), one single CTL can be
+ * shared across multiple CRTCs.
+ *
+ * Because the number of CTLs can be less than the number of CRTCs,
+ * CTLs are dynamically allocated from a pool of CTLs, only once a CRTC is
+ * requested by the client (in mdp5_crtc_mode_set()).
+ */
+
+struct mdp5_ctl {
+       struct mdp5_ctl_manager *ctlm;
+
+       u32 id;
+
+       /* whether this CTL has been allocated or not: */
+       bool busy;
+
+       /* memory output connection (@see mdp5_ctl_mode): */
+       u32 mode;
+
+       /* REG_MDP5_CTL_*(<id>) registers access info + lock: */
+       spinlock_t hw_lock;
+       u32 reg_offset;
+
+       /* flush mask used to commit CTL registers */
+       u32 flush_mask;
+
+       bool cursor_on;
+
+       struct drm_crtc *crtc;
+};
+
+struct mdp5_ctl_manager {
+       struct drm_device *dev;
+
+       /* number of CTL / Layer Mixers in this hw config: */
+       u32 nlm;
+       u32 nctl;
+
+       /* pool of CTLs + lock to protect resource allocation (ctls[i].busy) */
+       spinlock_t pool_lock;
+       struct mdp5_ctl ctls[MAX_CTL];
+};
+
+static inline
+struct mdp5_kms *get_kms(struct mdp5_ctl_manager *ctl_mgr)
+{
+       struct msm_drm_private *priv = ctl_mgr->dev->dev_private;
+
+       return to_mdp5_kms(to_mdp_kms(priv->kms));
+}
+
+static inline
+void ctl_write(struct mdp5_ctl *ctl, u32 reg, u32 data)
+{
+       struct mdp5_kms *mdp5_kms = get_kms(ctl->ctlm);
+
+       (void)ctl->reg_offset; /* TODO use this instead of mdp5_write */
+       mdp5_write(mdp5_kms, reg, data);
+}
+
+static inline
+u32 ctl_read(struct mdp5_ctl *ctl, u32 reg)
+{
+       struct mdp5_kms *mdp5_kms = get_kms(ctl->ctlm);
+
+       (void)ctl->reg_offset; /* TODO use this instead of mdp5_write */
+       return mdp5_read(mdp5_kms, reg);
+}
+
+
+int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, enum mdp5_intf intf)
+{
+       unsigned long flags;
+       static const enum mdp5_intfnum intfnum[] = {
+                       INTF0, INTF1, INTF2, INTF3,
+       };
+
+       spin_lock_irqsave(&ctl->hw_lock, flags);
+       ctl_write(ctl, REG_MDP5_CTL_OP(ctl->id),
+                       MDP5_CTL_OP_MODE(ctl->mode) |
+                       MDP5_CTL_OP_INTF_NUM(intfnum[intf]));
+       spin_unlock_irqrestore(&ctl->hw_lock, flags);
+
+       return 0;
+}
+
+int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable)
+{
+       struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
+       unsigned long flags;
+       u32 blend_cfg;
+       int lm;
+
+       lm = mdp5_crtc_get_lm(ctl->crtc);
+       if (unlikely(WARN_ON(lm < 0))) {
+               dev_err(ctl_mgr->dev->dev, "CTL %d cannot find LM: %d",
+                               ctl->id, lm);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&ctl->hw_lock, flags);
+
+       blend_cfg = ctl_read(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, lm));
+
+       if (enable)
+               blend_cfg |=  MDP5_CTL_LAYER_REG_CURSOR_OUT;
+       else
+               blend_cfg &= ~MDP5_CTL_LAYER_REG_CURSOR_OUT;
+
+       ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, lm), blend_cfg);
+
+       spin_unlock_irqrestore(&ctl->hw_lock, flags);
+
+       ctl->cursor_on = enable;
+
+       return 0;
+}
+
+
+int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg)
+{
+       unsigned long flags;
+
+       if (ctl->cursor_on)
+               blend_cfg |=  MDP5_CTL_LAYER_REG_CURSOR_OUT;
+       else
+               blend_cfg &= ~MDP5_CTL_LAYER_REG_CURSOR_OUT;
+
+       spin_lock_irqsave(&ctl->hw_lock, flags);
+       ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, lm), blend_cfg);
+       spin_unlock_irqrestore(&ctl->hw_lock, flags);
+
+       return 0;
+}
+
+int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask)
+{
+       struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
+       unsigned long flags;
+
+       if (flush_mask & MDP5_CTL_FLUSH_CURSOR_DUMMY) {
+               int lm = mdp5_crtc_get_lm(ctl->crtc);
+
+               if (unlikely(WARN_ON(lm < 0))) {
+                       dev_err(ctl_mgr->dev->dev, "CTL %d cannot find LM: %d",
+                                       ctl->id, lm);
+                       return -EINVAL;
+               }
+
+               /* for current targets, cursor bit is the same as LM bit */
+               flush_mask |= mdp_ctl_flush_mask_lm(lm);
+       }
+
+       spin_lock_irqsave(&ctl->hw_lock, flags);
+       ctl_write(ctl, REG_MDP5_CTL_FLUSH(ctl->id), flush_mask);
+       spin_unlock_irqrestore(&ctl->hw_lock, flags);
+
+       return 0;
+}
+
+u32 mdp5_ctl_get_flush(struct mdp5_ctl *ctl)
+{
+       return ctl->flush_mask;
+}
+
+void mdp5_ctl_release(struct mdp5_ctl *ctl)
+{
+       struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
+       unsigned long flags;
+
+       if (unlikely(WARN_ON(ctl->id >= MAX_CTL) || !ctl->busy)) {
+               dev_err(ctl_mgr->dev->dev, "CTL %d in bad state (%d)",
+                               ctl->id, ctl->busy);
+               return;
+       }
+
+       spin_lock_irqsave(&ctl_mgr->pool_lock, flags);
+       ctl->busy = false;
+       spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
+
+       DBG("CTL %d released", ctl->id);
+}
+
+/*
+ * mdp5_ctl_request() - CTL dynamic allocation
+ *
+ * Note: Current implementation considers that we can only have one CRTC per CTL
+ *
+ * @return first free CTL
+ */
+struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctl_mgr,
+               struct drm_crtc *crtc)
+{
+       struct mdp5_ctl *ctl = NULL;
+       unsigned long flags;
+       int c;
+
+       spin_lock_irqsave(&ctl_mgr->pool_lock, flags);
+
+       for (c = 0; c < ctl_mgr->nctl; c++)
+               if (!ctl_mgr->ctls[c].busy)
+                       break;
+
+       if (unlikely(c >= ctl_mgr->nctl)) {
+               dev_err(ctl_mgr->dev->dev, "No more CTL available!");
+               goto unlock;
+       }
+
+       ctl = &ctl_mgr->ctls[c];
+
+       ctl->crtc = crtc;
+       ctl->busy = true;
+       DBG("CTL %d allocated", ctl->id);
+
+unlock:
+       spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
+       return ctl;
+}
+
+void mdp5_ctlm_hw_reset(struct mdp5_ctl_manager *ctl_mgr)
+{
+       unsigned long flags;
+       int c;
+
+       for (c = 0; c < ctl_mgr->nctl; c++) {
+               struct mdp5_ctl *ctl = &ctl_mgr->ctls[c];
+
+               spin_lock_irqsave(&ctl->hw_lock, flags);
+               ctl_write(ctl, REG_MDP5_CTL_OP(ctl->id), 0);
+               spin_unlock_irqrestore(&ctl->hw_lock, flags);
+       }
+}
+
+void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctl_mgr)
+{
+       kfree(ctl_mgr);
+}
+
+struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
+               void __iomem *mmio_base, const struct mdp5_cfg_hw *hw_cfg)
+{
+       struct mdp5_ctl_manager *ctl_mgr;
+       const struct mdp5_sub_block *ctl_cfg = &hw_cfg->ctl;
+       unsigned long flags;
+       int c, ret;
+
+       ctl_mgr = kzalloc(sizeof(*ctl_mgr), GFP_KERNEL);
+       if (!ctl_mgr) {
+               dev_err(dev->dev, "failed to allocate CTL manager\n");
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       if (unlikely(WARN_ON(ctl_cfg->count > MAX_CTL))) {
+               dev_err(dev->dev, "Increase static pool size to at least %d\n",
+                               ctl_cfg->count);
+               ret = -ENOSPC;
+               goto fail;
+       }
+
+       /* initialize the CTL manager: */
+       ctl_mgr->dev = dev;
+       ctl_mgr->nlm = hw_cfg->lm.count;
+       ctl_mgr->nctl = ctl_cfg->count;
+       spin_lock_init(&ctl_mgr->pool_lock);
+
+       /* initialize each CTL of the pool: */
+       spin_lock_irqsave(&ctl_mgr->pool_lock, flags);
+       for (c = 0; c < ctl_mgr->nctl; c++) {
+               struct mdp5_ctl *ctl = &ctl_mgr->ctls[c];
+
+               if (WARN_ON(!ctl_cfg->base[c])) {
+                       dev_err(dev->dev, "CTL_%d: base is null!\n", c);
+                       ret = -EINVAL;
+                       goto fail;
+               }
+               ctl->ctlm = ctl_mgr;
+               ctl->id = c;
+               ctl->mode = MODE_NONE;
+               ctl->reg_offset = ctl_cfg->base[c];
+               ctl->flush_mask = MDP5_CTL_FLUSH_CTL;
+               ctl->busy = false;
+               spin_lock_init(&ctl->hw_lock);
+       }
+       spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags);
+       DBG("Pool of %d CTLs created.", ctl_mgr->nctl);
+
+       return ctl_mgr;
+
+fail:
+       if (ctl_mgr)
+               mdp5_ctlm_destroy(ctl_mgr);
+
+       return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h
new file mode 100644 (file)
index 0000000..1018519
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2014 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 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.
+ */
+
+#ifndef __MDP5_CTL_H__
+#define __MDP5_CTL_H__
+
+#include "msm_drv.h"
+
+/*
+ * CTL Manager prototypes:
+ * mdp5_ctlm_init() returns a ctlm (CTL Manager) handler,
+ * which is then used to call the other mdp5_ctlm_*(ctlm, ...) functions.
+ */
+struct mdp5_ctl_manager;
+struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
+               void __iomem *mmio_base, const struct mdp5_cfg_hw *hw_cfg);
+void mdp5_ctlm_hw_reset(struct mdp5_ctl_manager *ctlm);
+void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctlm);
+
+/*
+ * CTL prototypes:
+ * mdp5_ctl_request(ctlm, ...) returns a ctl (CTL resource) handler,
+ * which is then used to call the other mdp5_ctl_*(ctl, ...) functions.
+ */
+struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctlm, struct drm_crtc *crtc);
+
+int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, enum mdp5_intf intf);
+
+int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable);
+
+/* @blend_cfg: see LM blender config definition below */
+int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg);
+
+/* @flush_mask: see CTL flush masks definitions below */
+int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask);
+u32 mdp5_ctl_get_flush(struct mdp5_ctl *ctl);
+
+void mdp5_ctl_release(struct mdp5_ctl *ctl);
+
+/*
+ * blend_cfg (LM blender config):
+ *
+ * The function below allows the caller of mdp5_ctl_blend() to specify how pipes
+ * are being blended according to their stage (z-order), through @blend_cfg arg.
+ */
+static inline u32 mdp_ctl_blend_mask(enum mdp5_pipe pipe,
+               enum mdp_mixer_stage_id stage)
+{
+       switch (pipe) {
+       case SSPP_VIG0: return MDP5_CTL_LAYER_REG_VIG0(stage);
+       case SSPP_VIG1: return MDP5_CTL_LAYER_REG_VIG1(stage);
+       case SSPP_VIG2: return MDP5_CTL_LAYER_REG_VIG2(stage);
+       case SSPP_RGB0: return MDP5_CTL_LAYER_REG_RGB0(stage);
+       case SSPP_RGB1: return MDP5_CTL_LAYER_REG_RGB1(stage);
+       case SSPP_RGB2: return MDP5_CTL_LAYER_REG_RGB2(stage);
+       case SSPP_DMA0: return MDP5_CTL_LAYER_REG_DMA0(stage);
+       case SSPP_DMA1: return MDP5_CTL_LAYER_REG_DMA1(stage);
+       case SSPP_VIG3: return MDP5_CTL_LAYER_REG_VIG3(stage);
+       case SSPP_RGB3: return MDP5_CTL_LAYER_REG_RGB3(stage);
+       default:        return 0;
+       }
+}
+
+/*
+ * flush_mask (CTL flush masks):
+ *
+ * The following functions allow each DRM entity to get and store
+ * their own flush mask.
+ * Once stored, these masks will then be accessed through each DRM's
+ * interface and used by the caller of mdp5_ctl_commit() to specify
+ * which block(s) need to be flushed through @flush_mask parameter.
+ */
+
+#define MDP5_CTL_FLUSH_CURSOR_DUMMY    0x80000000
+
+static inline u32 mdp_ctl_flush_mask_cursor(int cursor_id)
+{
+       /* TODO: use id once multiple cursor support is present */
+       (void)cursor_id;
+
+       return MDP5_CTL_FLUSH_CURSOR_DUMMY;
+}
+
+static inline u32 mdp_ctl_flush_mask_lm(int lm)
+{
+       switch (lm) {
+       case 0:  return MDP5_CTL_FLUSH_LM0;
+       case 1:  return MDP5_CTL_FLUSH_LM1;
+       case 2:  return MDP5_CTL_FLUSH_LM2;
+       case 5:  return MDP5_CTL_FLUSH_LM5;
+       default: return 0;
+       }
+}
+
+static inline u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe)
+{
+       switch (pipe) {
+       case SSPP_VIG0: return MDP5_CTL_FLUSH_VIG0;
+       case SSPP_VIG1: return MDP5_CTL_FLUSH_VIG1;
+       case SSPP_VIG2: return MDP5_CTL_FLUSH_VIG2;
+       case SSPP_RGB0: return MDP5_CTL_FLUSH_RGB0;
+       case SSPP_RGB1: return MDP5_CTL_FLUSH_RGB1;
+       case SSPP_RGB2: return MDP5_CTL_FLUSH_RGB2;
+       case SSPP_DMA0: return MDP5_CTL_FLUSH_DMA0;
+       case SSPP_DMA1: return MDP5_CTL_FLUSH_DMA1;
+       case SSPP_VIG3: return MDP5_CTL_FLUSH_VIG3;
+       case SSPP_RGB3: return MDP5_CTL_FLUSH_RGB3;
+       default:        return 0;
+       }
+}
+
+#endif /* __MDP5_CTL_H__ */
index edec7bfaa952310b34216c362a35b61adeba5c4e..0254bfdeb92feb1b9aa3ccbab03c20c447877947 100644 (file)
@@ -24,6 +24,7 @@ struct mdp5_encoder {
        struct drm_encoder base;
        int intf;
        enum mdp5_intf intf_id;
+       spinlock_t intf_lock;   /* protect REG_MDP5_INTF_* registers */
        bool enabled;
        uint32_t bsc;
 };
@@ -115,6 +116,7 @@ static void mdp5_encoder_dpms(struct drm_encoder *encoder, int mode)
        struct mdp5_kms *mdp5_kms = get_kms(encoder);
        int intf = mdp5_encoder->intf;
        bool enabled = (mode == DRM_MODE_DPMS_ON);
+       unsigned long flags;
 
        DBG("mode=%d", mode);
 
@@ -123,9 +125,24 @@ static void mdp5_encoder_dpms(struct drm_encoder *encoder, int mode)
 
        if (enabled) {
                bs_set(mdp5_encoder, 1);
+               spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
                mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 1);
+               spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
        } else {
+               spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
                mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 0);
+               spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
+
+               /*
+                * Wait for a vsync so we know the ENABLE=0 latched before
+                * the (connector) source of the vsync's gets disabled,
+                * otherwise we end up in a funny state if we re-enable
+                * before the disable latches, which results that some of
+                * the settings changes for the new modeset (like new
+                * scanout buffer) don't latch properly..
+                */
+               mdp_irq_wait(&mdp5_kms->base, intf2vblank(intf));
+
                bs_set(mdp5_encoder, 0);
        }
 
@@ -150,6 +167,7 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
        uint32_t display_v_start, display_v_end;
        uint32_t hsync_start_x, hsync_end_x;
        uint32_t format;
+       unsigned long flags;
 
        mode = adjusted_mode;
 
@@ -180,6 +198,8 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
        display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + dtv_hsync_skew;
        display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + dtv_hsync_skew - 1;
 
+       spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
+
        mdp5_write(mdp5_kms, REG_MDP5_INTF_HSYNC_CTL(intf),
                        MDP5_INTF_HSYNC_CTL_PULSEW(mode->hsync_end - mode->hsync_start) |
                        MDP5_INTF_HSYNC_CTL_PERIOD(mode->htotal));
@@ -201,6 +221,8 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
        mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_VEND_F0(intf), 0);
        mdp5_write(mdp5_kms, REG_MDP5_INTF_PANEL_FORMAT(intf), format);
        mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(intf), 0x3);  /* frame+line? */
+
+       spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
 }
 
 static void mdp5_encoder_prepare(struct drm_encoder *encoder)
@@ -242,6 +264,8 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf,
        mdp5_encoder->intf_id = intf_id;
        encoder = &mdp5_encoder->base;
 
+       spin_lock_init(&mdp5_encoder->intf_lock);
+
        drm_encoder_init(dev, encoder, &mdp5_encoder_funcs,
                         DRM_MODE_ENCODER_TMDS);
        drm_encoder_helper_add(encoder, &mdp5_encoder_helper_funcs);
index f2b985bc2adf41f8330dd4bfb8dcafdb30b43c53..70ac81edd40f3bb7d6de68553b7be350005312ec 100644 (file)
@@ -15,6 +15,8 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
 
 #include "msm_drv.h"
 #include "mdp5_kms.h"
@@ -88,11 +90,17 @@ irqreturn_t mdp5_irq(struct msm_kms *kms)
 
        VERB("intr=%08x", intr);
 
-       if (intr & MDP5_HW_INTR_STATUS_INTR_MDP)
+       if (intr & MDP5_HW_INTR_STATUS_INTR_MDP) {
                mdp5_irq_mdp(mdp_kms);
+               intr &= ~MDP5_HW_INTR_STATUS_INTR_MDP;
+       }
 
-       if (intr & MDP5_HW_INTR_STATUS_INTR_HDMI)
-               hdmi_irq(0, mdp5_kms->hdmi);
+       while (intr) {
+               irq_hw_number_t hwirq = fls(intr) - 1;
+               generic_handle_irq(irq_find_mapping(
+                               mdp5_kms->irqcontroller.domain, hwirq));
+               intr &= ~(1 << hwirq);
+       }
 
        return IRQ_HANDLED;
 }
@@ -109,3 +117,82 @@ void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
        mdp_update_vblank_mask(to_mdp_kms(kms),
                        mdp5_crtc_vblank(crtc), false);
 }
+
+/*
+ * interrupt-controller implementation, so sub-blocks (hdmi/eDP/dsi/etc)
+ * can register to get their irq's delivered
+ */
+
+#define VALID_IRQS  (MDP5_HW_INTR_STATUS_INTR_DSI0 | \
+               MDP5_HW_INTR_STATUS_INTR_DSI1 | \
+               MDP5_HW_INTR_STATUS_INTR_HDMI | \
+               MDP5_HW_INTR_STATUS_INTR_EDP)
+
+static void mdp5_hw_mask_irq(struct irq_data *irqd)
+{
+       struct mdp5_kms *mdp5_kms = irq_data_get_irq_chip_data(irqd);
+       smp_mb__before_atomic();
+       clear_bit(irqd->hwirq, &mdp5_kms->irqcontroller.enabled_mask);
+       smp_mb__after_atomic();
+}
+
+static void mdp5_hw_unmask_irq(struct irq_data *irqd)
+{
+       struct mdp5_kms *mdp5_kms = irq_data_get_irq_chip_data(irqd);
+       smp_mb__before_atomic();
+       set_bit(irqd->hwirq, &mdp5_kms->irqcontroller.enabled_mask);
+       smp_mb__after_atomic();
+}
+
+static struct irq_chip mdp5_hw_irq_chip = {
+       .name           = "mdp5",
+       .irq_mask       = mdp5_hw_mask_irq,
+       .irq_unmask     = mdp5_hw_unmask_irq,
+};
+
+static int mdp5_hw_irqdomain_map(struct irq_domain *d,
+               unsigned int irq, irq_hw_number_t hwirq)
+{
+       struct mdp5_kms *mdp5_kms = d->host_data;
+
+       if (!(VALID_IRQS & (1 << hwirq)))
+               return -EPERM;
+
+       irq_set_chip_and_handler(irq, &mdp5_hw_irq_chip, handle_level_irq);
+       irq_set_chip_data(irq, mdp5_kms);
+       set_irq_flags(irq, IRQF_VALID);
+
+       return 0;
+}
+
+static struct irq_domain_ops mdp5_hw_irqdomain_ops = {
+       .map = mdp5_hw_irqdomain_map,
+       .xlate = irq_domain_xlate_onecell,
+};
+
+
+int mdp5_irq_domain_init(struct mdp5_kms *mdp5_kms)
+{
+       struct device *dev = mdp5_kms->dev->dev;
+       struct irq_domain *d;
+
+       d = irq_domain_add_linear(dev->of_node, 32,
+                       &mdp5_hw_irqdomain_ops, mdp5_kms);
+       if (!d) {
+               dev_err(dev, "mdp5 irq domain add failed\n");
+               return -ENXIO;
+       }
+
+       mdp5_kms->irqcontroller.enabled_mask = 0;
+       mdp5_kms->irqcontroller.domain = d;
+
+       return 0;
+}
+
+void mdp5_irq_domain_fini(struct mdp5_kms *mdp5_kms)
+{
+       if (mdp5_kms->irqcontroller.domain) {
+               irq_domain_remove(mdp5_kms->irqcontroller.domain);
+               mdp5_kms->irqcontroller.domain = NULL;
+       }
+}
index 31a2c6331a1d5a47c57bb36e1a30482b67615e50..a11f1b80c488567d44755ad68eadc4d15dc61375 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -24,145 +25,11 @@ static const char *iommu_ports[] = {
                "mdp_0",
 };
 
-static struct mdp5_platform_config *mdp5_get_config(struct platform_device *dev);
-
-const struct mdp5_config *mdp5_cfg;
-
-static const struct mdp5_config msm8x74_config = {
-       .name = "msm8x74",
-       .ctl = {
-               .count = 5,
-               .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 },
-       },
-       .pipe_vig = {
-               .count = 3,
-               .base = { 0x01200, 0x01600, 0x01a00 },
-       },
-       .pipe_rgb = {
-               .count = 3,
-               .base = { 0x01e00, 0x02200, 0x02600 },
-       },
-       .pipe_dma = {
-               .count = 2,
-               .base = { 0x02a00, 0x02e00 },
-       },
-       .lm = {
-               .count = 5,
-               .base = { 0x03200, 0x03600, 0x03a00, 0x03e00, 0x04200 },
-       },
-       .dspp = {
-               .count = 3,
-               .base = { 0x04600, 0x04a00, 0x04e00 },
-       },
-       .ad = {
-               .count = 2,
-               .base = { 0x13100, 0x13300 }, /* NOTE: no ad in v1.0 */
-       },
-       .intf = {
-               .count = 4,
-               .base = { 0x12500, 0x12700, 0x12900, 0x12b00 },
-       },
-};
-
-static const struct mdp5_config apq8084_config = {
-       .name = "apq8084",
-       .ctl = {
-               .count = 5,
-               .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 },
-       },
-       .pipe_vig = {
-               .count = 4,
-               .base = { 0x01200, 0x01600, 0x01a00, 0x01e00 },
-       },
-       .pipe_rgb = {
-               .count = 4,
-               .base = { 0x02200, 0x02600, 0x02a00, 0x02e00 },
-       },
-       .pipe_dma = {
-               .count = 2,
-               .base = { 0x03200, 0x03600 },
-       },
-       .lm = {
-               .count = 6,
-               .base = { 0x03a00, 0x03e00, 0x04200, 0x04600, 0x04a00, 0x04e00 },
-       },
-       .dspp = {
-               .count = 4,
-               .base = { 0x05200, 0x05600, 0x05a00, 0x05e00 },
-
-       },
-       .ad = {
-               .count = 3,
-               .base = { 0x13500, 0x13700, 0x13900 },
-       },
-       .intf = {
-               .count = 5,
-               .base = { 0x12500, 0x12700, 0x12900, 0x12b00, 0x12d00 },
-       },
-};
-
-struct mdp5_config_entry {
-       int revision;
-       const struct mdp5_config *config;
-};
-
-static const struct mdp5_config_entry mdp5_configs[] = {
-       { .revision = 0, .config = &msm8x74_config },
-       { .revision = 2, .config = &msm8x74_config },
-       { .revision = 3, .config = &apq8084_config },
-};
-
-static int mdp5_select_hw_cfg(struct msm_kms *kms)
-{
-       struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
-       struct drm_device *dev = mdp5_kms->dev;
-       uint32_t version, major, minor;
-       int i, ret = 0;
-
-       mdp5_enable(mdp5_kms);
-       version = mdp5_read(mdp5_kms, REG_MDP5_MDP_VERSION);
-       mdp5_disable(mdp5_kms);
-
-       major = FIELD(version, MDP5_MDP_VERSION_MAJOR);
-       minor = FIELD(version, MDP5_MDP_VERSION_MINOR);
-
-       DBG("found MDP5 version v%d.%d", major, minor);
-
-       if (major != 1) {
-               dev_err(dev->dev, "unexpected MDP major version: v%d.%d\n",
-                               major, minor);
-               ret = -ENXIO;
-               goto out;
-       }
-
-       mdp5_kms->rev = minor;
-
-       /* only after mdp5_cfg global pointer's init can we access the hw */
-       for (i = 0; i < ARRAY_SIZE(mdp5_configs); i++) {
-               if (mdp5_configs[i].revision != minor)
-                       continue;
-               mdp5_kms->hw_cfg = mdp5_cfg = mdp5_configs[i].config;
-               break;
-       }
-       if (unlikely(!mdp5_kms->hw_cfg)) {
-               dev_err(dev->dev, "unexpected MDP minor revision: v%d.%d\n",
-                               major, minor);
-               ret = -ENXIO;
-               goto out;
-       }
-
-       DBG("MDP5: %s config selected", mdp5_kms->hw_cfg->name);
-
-       return 0;
-out:
-       return ret;
-}
-
 static int mdp5_hw_init(struct msm_kms *kms)
 {
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
        struct drm_device *dev = mdp5_kms->dev;
-       int i;
+       unsigned long flags;
 
        pm_runtime_get_sync(dev->dev);
 
@@ -190,10 +57,11 @@ static int mdp5_hw_init(struct msm_kms *kms)
         * care.
         */
 
+       spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
        mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, 0);
+       spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
 
-       for (i = 0; i < mdp5_kms->hw_cfg->ctl.count; i++)
-               mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(i), 0);
+       mdp5_ctlm_hw_reset(mdp5_kms->ctlm);
 
        pm_runtime_put_sync(dev->dev);
 
@@ -221,10 +89,20 @@ static void mdp5_destroy(struct msm_kms *kms)
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
        struct msm_mmu *mmu = mdp5_kms->mmu;
 
+       mdp5_irq_domain_fini(mdp5_kms);
+
        if (mmu) {
                mmu->funcs->detach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports));
                mmu->funcs->destroy(mmu);
        }
+
+       if (mdp5_kms->ctlm)
+               mdp5_ctlm_destroy(mdp5_kms->ctlm);
+       if (mdp5_kms->smp)
+               mdp5_smp_destroy(mdp5_kms->smp);
+       if (mdp5_kms->cfg)
+               mdp5_cfg_destroy(mdp5_kms->cfg);
+
        kfree(mdp5_kms);
 }
 
@@ -274,17 +152,31 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
        static const enum mdp5_pipe crtcs[] = {
                        SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, SSPP_RGB3,
        };
+       static const enum mdp5_pipe pub_planes[] = {
+                       SSPP_VIG0, SSPP_VIG1, SSPP_VIG2, SSPP_VIG3,
+       };
        struct drm_device *dev = mdp5_kms->dev;
        struct msm_drm_private *priv = dev->dev_private;
        struct drm_encoder *encoder;
+       const struct mdp5_cfg_hw *hw_cfg;
        int i, ret;
 
-       /* construct CRTCs: */
-       for (i = 0; i < mdp5_kms->hw_cfg->pipe_rgb.count; i++) {
+       hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
+
+       /* register our interrupt-controller for hdmi/eDP/dsi/etc
+        * to use for irqs routed through mdp:
+        */
+       ret = mdp5_irq_domain_init(mdp5_kms);
+       if (ret)
+               goto fail;
+
+       /* construct CRTCs and their private planes: */
+       for (i = 0; i < hw_cfg->pipe_rgb.count; i++) {
                struct drm_plane *plane;
                struct drm_crtc *crtc;
 
-               plane = mdp5_plane_init(dev, crtcs[i], true);
+               plane = mdp5_plane_init(dev, crtcs[i], true,
+                               hw_cfg->pipe_rgb.base[i]);
                if (IS_ERR(plane)) {
                        ret = PTR_ERR(plane);
                        dev_err(dev->dev, "failed to construct plane for %s (%d)\n",
@@ -302,6 +194,20 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
                priv->crtcs[priv->num_crtcs++] = crtc;
        }
 
+       /* Construct public planes: */
+       for (i = 0; i < hw_cfg->pipe_vig.count; i++) {
+               struct drm_plane *plane;
+
+               plane = mdp5_plane_init(dev, pub_planes[i], false,
+                               hw_cfg->pipe_vig.base[i]);
+               if (IS_ERR(plane)) {
+                       ret = PTR_ERR(plane);
+                       dev_err(dev->dev, "failed to construct %s plane: %d\n",
+                                       pipe2name(pub_planes[i]), ret);
+                       goto fail;
+               }
+       }
+
        /* Construct encoder for HDMI: */
        encoder = mdp5_encoder_init(dev, 3, INTF_HDMI);
        if (IS_ERR(encoder)) {
@@ -324,11 +230,12 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
        priv->encoders[priv->num_encoders++] = encoder;
 
        /* Construct bridge/connector for HDMI: */
-       mdp5_kms->hdmi = hdmi_init(dev, encoder);
-       if (IS_ERR(mdp5_kms->hdmi)) {
-               ret = PTR_ERR(mdp5_kms->hdmi);
-               dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
-               goto fail;
+       if (priv->hdmi) {
+               ret = hdmi_modeset_init(priv->hdmi, dev, encoder);
+               if (ret) {
+                       dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
+                       goto fail;
+               }
        }
 
        return 0;
@@ -337,6 +244,21 @@ fail:
        return ret;
 }
 
+static void read_hw_revision(struct mdp5_kms *mdp5_kms,
+               uint32_t *major, uint32_t *minor)
+{
+       uint32_t version;
+
+       mdp5_enable(mdp5_kms);
+       version = mdp5_read(mdp5_kms, REG_MDP5_MDP_VERSION);
+       mdp5_disable(mdp5_kms);
+
+       *major = FIELD(version, MDP5_MDP_VERSION_MAJOR);
+       *minor = FIELD(version, MDP5_MDP_VERSION_MINOR);
+
+       DBG("MDP5 version v%d.%d", *major, *minor);
+}
+
 static int get_clk(struct platform_device *pdev, struct clk **clkp,
                const char *name)
 {
@@ -353,10 +275,11 @@ static int get_clk(struct platform_device *pdev, struct clk **clkp,
 struct msm_kms *mdp5_kms_init(struct drm_device *dev)
 {
        struct platform_device *pdev = dev->platformdev;
-       struct mdp5_platform_config *config = mdp5_get_config(pdev);
+       struct mdp5_cfg *config;
        struct mdp5_kms *mdp5_kms;
        struct msm_kms *kms = NULL;
        struct msm_mmu *mmu;
+       uint32_t major, minor;
        int i, ret;
 
        mdp5_kms = kzalloc(sizeof(*mdp5_kms), GFP_KERNEL);
@@ -366,12 +289,13 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
                goto fail;
        }
 
+       spin_lock_init(&mdp5_kms->resource_lock);
+
        mdp_kms_init(&mdp5_kms->base, &kms_funcs);
 
        kms = &mdp5_kms->base.base;
 
        mdp5_kms->dev = dev;
-       mdp5_kms->smp_blk_cnt = config->smp_blk_cnt;
 
        mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys", "MDP5");
        if (IS_ERR(mdp5_kms->mmio)) {
@@ -416,24 +340,52 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
        if (ret)
                goto fail;
 
-       ret = clk_set_rate(mdp5_kms->src_clk, config->max_clk);
+       /* we need to set a default rate before enabling.  Set a safe
+        * rate first, then figure out hw revision, and then set a
+        * more optimal rate:
+        */
+       clk_set_rate(mdp5_kms->src_clk, 200000000);
+
+       read_hw_revision(mdp5_kms, &major, &minor);
 
-       ret = mdp5_select_hw_cfg(kms);
-       if (ret)
+       mdp5_kms->cfg = mdp5_cfg_init(mdp5_kms, major, minor);
+       if (IS_ERR(mdp5_kms->cfg)) {
+               ret = PTR_ERR(mdp5_kms->cfg);
+               mdp5_kms->cfg = NULL;
                goto fail;
+       }
+
+       config = mdp5_cfg_get_config(mdp5_kms->cfg);
+
+       /* TODO: compute core clock rate at runtime */
+       clk_set_rate(mdp5_kms->src_clk, config->hw->max_clk);
+
+       mdp5_kms->smp = mdp5_smp_init(mdp5_kms->dev, &config->hw->smp);
+       if (IS_ERR(mdp5_kms->smp)) {
+               ret = PTR_ERR(mdp5_kms->smp);
+               mdp5_kms->smp = NULL;
+               goto fail;
+       }
+
+       mdp5_kms->ctlm = mdp5_ctlm_init(dev, mdp5_kms->mmio, config->hw);
+       if (IS_ERR(mdp5_kms->ctlm)) {
+               ret = PTR_ERR(mdp5_kms->ctlm);
+               mdp5_kms->ctlm = NULL;
+               goto fail;
+       }
 
        /* make sure things are off before attaching iommu (bootloader could
         * have left things on, in which case we'll start getting faults if
         * we don't disable):
         */
        mdp5_enable(mdp5_kms);
-       for (i = 0; i < mdp5_kms->hw_cfg->intf.count; i++)
+       for (i = 0; i < config->hw->intf.count; i++)
                mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0);
        mdp5_disable(mdp5_kms);
        mdelay(16);
 
-       if (config->iommu) {
-               mmu = msm_iommu_new(&pdev->dev, config->iommu);
+       if (config->platform.iommu) {
+               mmu = msm_iommu_new(&pdev->dev, config->platform.iommu);
                if (IS_ERR(mmu)) {
                        ret = PTR_ERR(mmu);
                        dev_err(dev->dev, "failed to init iommu: %d\n", ret);
@@ -474,18 +426,3 @@ fail:
                mdp5_destroy(kms);
        return ERR_PTR(ret);
 }
-
-static struct mdp5_platform_config *mdp5_get_config(struct platform_device *dev)
-{
-       static struct mdp5_platform_config config = {};
-#ifdef CONFIG_OF
-       /* TODO */
-#endif
-       config.iommu = iommu_domain_alloc(&platform_bus_type);
-       /* TODO hard-coded in downstream mdss, but should it be? */
-       config.max_clk = 200000000;
-       /* TODO get from DT: */
-       config.smp_blk_cnt = 22;
-
-       return &config;
-}
index 5bf340dd0f00afc05300fa0e68346acb005e59c4..dd69c77c0d64f3b1e4928850555d93292c1dbf9d 100644 (file)
 #include "msm_drv.h"
 #include "msm_kms.h"
 #include "mdp/mdp_kms.h"
-/* dynamic offsets used by mdp5.xml.h (initialized in mdp5_kms.c) */
-#define MDP5_MAX_BASES         8
-struct mdp5_sub_block {
-       int     count;
-       uint32_t base[MDP5_MAX_BASES];
-};
-struct mdp5_config {
-       char  *name;
-       struct mdp5_sub_block ctl;
-       struct mdp5_sub_block pipe_vig;
-       struct mdp5_sub_block pipe_rgb;
-       struct mdp5_sub_block pipe_dma;
-       struct mdp5_sub_block lm;
-       struct mdp5_sub_block dspp;
-       struct mdp5_sub_block ad;
-       struct mdp5_sub_block intf;
-};
-extern const struct mdp5_config *mdp5_cfg;
+#include "mdp5_cfg.h"  /* must be included before mdp5.xml.h */
 #include "mdp5.xml.h"
+#include "mdp5_ctl.h"
 #include "mdp5_smp.h"
 
 struct mdp5_kms {
@@ -47,17 +31,14 @@ struct mdp5_kms {
 
        struct drm_device *dev;
 
-       int rev;
-       const struct mdp5_config *hw_cfg;
+       struct mdp5_cfg_handler *cfg;
 
        /* mapper-id used to request GEM buffer mapped for scanout: */
        int id;
        struct msm_mmu *mmu;
 
-       /* for tracking smp allocation amongst pipes: */
-       mdp5_smp_state_t smp_state;
-       struct mdp5_client_smp_state smp_client_state[CID_MAX];
-       int smp_blk_cnt;
+       struct mdp5_smp *smp;
+       struct mdp5_ctl_manager *ctlm;
 
        /* io/register spaces: */
        void __iomem *mmio, *vbif;
@@ -71,18 +52,47 @@ struct mdp5_kms {
        struct clk *lut_clk;
        struct clk *vsync_clk;
 
-       struct hdmi *hdmi;
+       /*
+        * lock to protect access to global resources: ie., following register:
+        *      - REG_MDP5_DISP_INTF_SEL
+        */
+       spinlock_t resource_lock;
 
        struct mdp_irq error_handler;
+
+       struct {
+               volatile unsigned long enabled_mask;
+               struct irq_domain *domain;
+       } irqcontroller;
 };
 #define to_mdp5_kms(x) container_of(x, struct mdp5_kms, base)
 
-/* platform config data (ie. from DT, or pdata) */
-struct mdp5_platform_config {
-       struct iommu_domain *iommu;
-       uint32_t max_clk;
-       int smp_blk_cnt;
+struct mdp5_plane_state {
+       struct drm_plane_state base;
+
+       /* "virtual" zpos.. we calculate actual mixer-stage at runtime
+        * by sorting the attached planes by zpos and then assigning
+        * mixer stage lowest to highest.  Private planes get default
+        * zpos of zero, and public planes a unique value that is
+        * greater than zero.  This way, things work out if a naive
+        * userspace assigns planes to a crtc without setting zpos.
+        */
+       int zpos;
+
+       /* the actual mixer stage, calculated in crtc->atomic_check()
+        * NOTE: this should move to mdp5_crtc_state, when that exists
+        */
+       enum mdp_mixer_stage_id stage;
+
+       /* some additional transactional status to help us know in the
+        * apply path whether we need to update SMP allocation, and
+        * whether current update is still pending:
+        */
+       bool mode_changed : 1;
+       bool pending : 1;
 };
+#define to_mdp5_plane_state(x) \
+               container_of(x, struct mdp5_plane_state, base)
 
 static inline void mdp5_write(struct mdp5_kms *mdp5_kms, u32 reg, u32 data)
 {
@@ -107,23 +117,6 @@ static inline const char *pipe2name(enum mdp5_pipe pipe)
        return names[pipe];
 }
 
-static inline uint32_t pipe2flush(enum mdp5_pipe pipe)
-{
-       switch (pipe) {
-       case SSPP_VIG0: return MDP5_CTL_FLUSH_VIG0;
-       case SSPP_VIG1: return MDP5_CTL_FLUSH_VIG1;
-       case SSPP_VIG2: return MDP5_CTL_FLUSH_VIG2;
-       case SSPP_RGB0: return MDP5_CTL_FLUSH_RGB0;
-       case SSPP_RGB1: return MDP5_CTL_FLUSH_RGB1;
-       case SSPP_RGB2: return MDP5_CTL_FLUSH_RGB2;
-       case SSPP_DMA0: return MDP5_CTL_FLUSH_DMA0;
-       case SSPP_DMA1: return MDP5_CTL_FLUSH_DMA1;
-       case SSPP_VIG3: return MDP5_CTL_FLUSH_VIG3;
-       case SSPP_RGB3: return MDP5_CTL_FLUSH_RGB3;
-       default:        return 0;
-       }
-}
-
 static inline int pipe2nclients(enum mdp5_pipe pipe)
 {
        switch (pipe) {
@@ -137,34 +130,6 @@ static inline int pipe2nclients(enum mdp5_pipe pipe)
        }
 }
 
-static inline enum mdp5_client_id pipe2client(enum mdp5_pipe pipe, int plane)
-{
-       WARN_ON(plane >= pipe2nclients(pipe));
-       switch (pipe) {
-       case SSPP_VIG0: return CID_VIG0_Y + plane;
-       case SSPP_VIG1: return CID_VIG1_Y + plane;
-       case SSPP_VIG2: return CID_VIG2_Y + plane;
-       case SSPP_RGB0: return CID_RGB0;
-       case SSPP_RGB1: return CID_RGB1;
-       case SSPP_RGB2: return CID_RGB2;
-       case SSPP_DMA0: return CID_DMA0_Y + plane;
-       case SSPP_DMA1: return CID_DMA1_Y + plane;
-       case SSPP_VIG3: return CID_VIG3_Y + plane;
-       case SSPP_RGB3: return CID_RGB3;
-       default:        return CID_UNUSED;
-       }
-}
-
-static inline uint32_t mixer2flush(int lm)
-{
-       switch (lm) {
-       case 0:  return MDP5_CTL_FLUSH_LM0;
-       case 1:  return MDP5_CTL_FLUSH_LM1;
-       case 2:  return MDP5_CTL_FLUSH_LM2;
-       default: return 0;
-       }
-}
-
 static inline uint32_t intf2err(int intf)
 {
        switch (intf) {
@@ -197,6 +162,8 @@ void mdp5_irq_uninstall(struct msm_kms *kms);
 irqreturn_t mdp5_irq(struct msm_kms *kms);
 int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
 void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
+int mdp5_irq_domain_init(struct mdp5_kms *mdp5_kms);
+void mdp5_irq_domain_fini(struct mdp5_kms *mdp5_kms);
 
 static inline
 uint32_t mdp5_get_formats(enum mdp5_pipe pipe, uint32_t *pixel_formats,
@@ -210,26 +177,18 @@ uint32_t mdp5_get_formats(enum mdp5_pipe pipe, uint32_t *pixel_formats,
 
 void mdp5_plane_install_properties(struct drm_plane *plane,
                struct drm_mode_object *obj);
-void mdp5_plane_set_scanout(struct drm_plane *plane,
-               struct drm_framebuffer *fb);
-int mdp5_plane_mode_set(struct drm_plane *plane,
-               struct drm_crtc *crtc, struct drm_framebuffer *fb,
-               int crtc_x, int crtc_y,
-               unsigned int crtc_w, unsigned int crtc_h,
-               uint32_t src_x, uint32_t src_y,
-               uint32_t src_w, uint32_t src_h);
+uint32_t mdp5_plane_get_flush(struct drm_plane *plane);
 void mdp5_plane_complete_flip(struct drm_plane *plane);
 enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane);
 struct drm_plane *mdp5_plane_init(struct drm_device *dev,
-               enum mdp5_pipe pipe, bool private_plane);
+               enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset);
 
 uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc);
 
+int mdp5_crtc_get_lm(struct drm_crtc *crtc);
 void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file);
 void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf,
                enum mdp5_intf intf_id);
-void mdp5_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane);
-void mdp5_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane);
 struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
                struct drm_plane *plane, int id);
 
index f3daec4412ad3e9fd6b8f7303a2b27280df7442c..26e5fdea6594c7d23854bc566ffe618453c455dd 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2014 The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -17,6 +18,7 @@
 
 #include "mdp5_kms.h"
 
+#define MAX_PLANE      4
 
 struct mdp5_plane {
        struct drm_plane base;
@@ -24,6 +26,11 @@ struct mdp5_plane {
 
        enum mdp5_pipe pipe;
 
+       spinlock_t pipe_lock;   /* protect REG_MDP5_PIPE_* registers */
+       uint32_t reg_offset;
+
+       uint32_t flush_mask;    /* used to commit pipe registers */
+
        uint32_t nformats;
        uint32_t formats[32];
 
@@ -31,31 +38,24 @@ struct mdp5_plane {
 };
 #define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base)
 
+static int mdp5_plane_mode_set(struct drm_plane *plane,
+               struct drm_crtc *crtc, struct drm_framebuffer *fb,
+               int crtc_x, int crtc_y,
+               unsigned int crtc_w, unsigned int crtc_h,
+               uint32_t src_x, uint32_t src_y,
+               uint32_t src_w, uint32_t src_h);
+static void set_scanout_locked(struct drm_plane *plane,
+               struct drm_framebuffer *fb);
+
 static struct mdp5_kms *get_kms(struct drm_plane *plane)
 {
        struct msm_drm_private *priv = plane->dev->dev_private;
        return to_mdp5_kms(to_mdp_kms(priv->kms));
 }
 
-static int mdp5_plane_update(struct drm_plane *plane,
-               struct drm_crtc *crtc, struct drm_framebuffer *fb,
-               int crtc_x, int crtc_y,
-               unsigned int crtc_w, unsigned int crtc_h,
-               uint32_t src_x, uint32_t src_y,
-               uint32_t src_w, uint32_t src_h)
+static bool plane_enabled(struct drm_plane_state *state)
 {
-       struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
-
-       mdp5_plane->enabled = true;
-
-       if (plane->fb)
-               drm_framebuffer_unreference(plane->fb);
-
-       drm_framebuffer_reference(fb);
-
-       return mdp5_plane_mode_set(plane, crtc, fb,
-                       crtc_x, crtc_y, crtc_w, crtc_h,
-                       src_x, src_y, src_w, src_h);
+       return state->fb && state->crtc;
 }
 
 static int mdp5_plane_disable(struct drm_plane *plane)
@@ -63,21 +63,13 @@ static int mdp5_plane_disable(struct drm_plane *plane)
        struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
        struct mdp5_kms *mdp5_kms = get_kms(plane);
        enum mdp5_pipe pipe = mdp5_plane->pipe;
-       int i;
 
        DBG("%s: disable", mdp5_plane->name);
 
-       /* update our SMP request to zero (release all our blks): */
-       for (i = 0; i < pipe2nclients(pipe); i++)
-               mdp5_smp_request(mdp5_kms, pipe2client(pipe, i), 0);
-
-       /* TODO detaching now will cause us not to get the last
-        * vblank and mdp5_smp_commit().. so other planes will
-        * still see smp blocks previously allocated to us as
-        * in-use..
-        */
-       if (plane->crtc)
-               mdp5_crtc_detach(plane->crtc, plane);
+       if (mdp5_kms) {
+               /* Release the memory we requested earlier from the SMP: */
+               mdp5_smp_release(mdp5_kms->smp, pipe);
+       }
 
        return 0;
 }
@@ -85,11 +77,8 @@ static int mdp5_plane_disable(struct drm_plane *plane)
 static void mdp5_plane_destroy(struct drm_plane *plane)
 {
        struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
-       struct msm_drm_private *priv = plane->dev->dev_private;
-
-       if (priv->kms)
-               mdp5_plane_disable(plane);
 
+       drm_plane_helper_disable(plane);
        drm_plane_cleanup(plane);
 
        kfree(mdp5_plane);
@@ -109,109 +98,186 @@ int mdp5_plane_set_property(struct drm_plane *plane,
        return -EINVAL;
 }
 
+static void mdp5_plane_reset(struct drm_plane *plane)
+{
+       struct mdp5_plane_state *mdp5_state;
+
+       if (plane->state && plane->state->fb)
+               drm_framebuffer_unreference(plane->state->fb);
+
+       kfree(to_mdp5_plane_state(plane->state));
+       mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL);
+
+       if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
+               mdp5_state->zpos = 0;
+       } else {
+               mdp5_state->zpos = 1 + drm_plane_index(plane);
+       }
+
+       plane->state = &mdp5_state->base;
+}
+
+static struct drm_plane_state *
+mdp5_plane_duplicate_state(struct drm_plane *plane)
+{
+       struct mdp5_plane_state *mdp5_state;
+
+       if (WARN_ON(!plane->state))
+               return NULL;
+
+       mdp5_state = kmemdup(to_mdp5_plane_state(plane->state),
+                       sizeof(*mdp5_state), GFP_KERNEL);
+
+       if (mdp5_state && mdp5_state->base.fb)
+               drm_framebuffer_reference(mdp5_state->base.fb);
+
+       mdp5_state->mode_changed = false;
+       mdp5_state->pending = false;
+
+       return &mdp5_state->base;
+}
+
+static void mdp5_plane_destroy_state(struct drm_plane *plane,
+               struct drm_plane_state *state)
+{
+       if (state->fb)
+               drm_framebuffer_unreference(state->fb);
+
+       kfree(to_mdp5_plane_state(state));
+}
+
 static const struct drm_plane_funcs mdp5_plane_funcs = {
-               .update_plane = mdp5_plane_update,
-               .disable_plane = mdp5_plane_disable,
+               .update_plane = drm_atomic_helper_update_plane,
+               .disable_plane = drm_atomic_helper_disable_plane,
                .destroy = mdp5_plane_destroy,
                .set_property = mdp5_plane_set_property,
+               .reset = mdp5_plane_reset,
+               .atomic_duplicate_state = mdp5_plane_duplicate_state,
+               .atomic_destroy_state = mdp5_plane_destroy_state,
 };
 
-void mdp5_plane_set_scanout(struct drm_plane *plane,
+static int mdp5_plane_prepare_fb(struct drm_plane *plane,
                struct drm_framebuffer *fb)
 {
        struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
        struct mdp5_kms *mdp5_kms = get_kms(plane);
-       enum mdp5_pipe pipe = mdp5_plane->pipe;
-       uint32_t nplanes = drm_format_num_planes(fb->pixel_format);
-       uint32_t iova[4];
-       int i;
-
-       for (i = 0; i < nplanes; i++) {
-               struct drm_gem_object *bo = msm_framebuffer_bo(fb, i);
-               msm_gem_get_iova(bo, mdp5_kms->id, &iova[i]);
-       }
-       for (; i < 4; i++)
-               iova[i] = 0;
 
-       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_A(pipe),
-                       MDP5_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) |
-                       MDP5_PIPE_SRC_STRIDE_A_P1(fb->pitches[1]));
-
-       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_B(pipe),
-                       MDP5_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) |
-                       MDP5_PIPE_SRC_STRIDE_B_P3(fb->pitches[3]));
-
-       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC0_ADDR(pipe), iova[0]);
-       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC1_ADDR(pipe), iova[1]);
-       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe), iova[2]);
-       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe), iova[3]);
-
-       plane->fb = fb;
+       DBG("%s: prepare: FB[%u]", mdp5_plane->name, fb->base.id);
+       return msm_framebuffer_prepare(fb, mdp5_kms->id);
 }
 
-/* NOTE: looks like if horizontal decimation is used (if we supported that)
- * then the width used to calculate SMP block requirements is the post-
- * decimated width.  Ie. SMP buffering sits downstream of decimation (which
- * presumably happens during the dma from scanout buffer).
- */
-static int request_smp_blocks(struct drm_plane *plane, uint32_t format,
-               uint32_t nplanes, uint32_t width)
+static void mdp5_plane_cleanup_fb(struct drm_plane *plane,
+               struct drm_framebuffer *fb)
 {
-       struct drm_device *dev = plane->dev;
        struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
        struct mdp5_kms *mdp5_kms = get_kms(plane);
-       enum mdp5_pipe pipe = mdp5_plane->pipe;
-       int i, hsub, nlines, nblks, ret;
 
-       hsub = drm_format_horz_chroma_subsampling(format);
+       DBG("%s: cleanup: FB[%u]", mdp5_plane->name, fb->base.id);
+       msm_framebuffer_cleanup(fb, mdp5_kms->id);
+}
 
-       /* different if BWC (compressed framebuffer?) enabled: */
-       nlines = 2;
+static int mdp5_plane_atomic_check(struct drm_plane *plane,
+               struct drm_plane_state *state)
+{
+       struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
+       struct drm_plane_state *old_state = plane->state;
 
-       for (i = 0, nblks = 0; i < nplanes; i++) {
-               int n, fetch_stride, cpp;
+       DBG("%s: check (%d -> %d)", mdp5_plane->name,
+                       plane_enabled(old_state), plane_enabled(state));
 
-               cpp = drm_format_plane_cpp(format, i);
-               fetch_stride = width * cpp / (i ? hsub : 1);
+       if (plane_enabled(state) && plane_enabled(old_state)) {
+               /* we cannot change SMP block configuration during scanout: */
+               bool full_modeset = false;
+               if (state->fb->pixel_format != old_state->fb->pixel_format) {
+                       DBG("%s: pixel_format change!", mdp5_plane->name);
+                       full_modeset = true;
+               }
+               if (state->src_w != old_state->src_w) {
+                       DBG("%s: src_w change!", mdp5_plane->name);
+                       full_modeset = true;
+               }
+               if (to_mdp5_plane_state(old_state)->pending) {
+                       DBG("%s: still pending!", mdp5_plane->name);
+                       full_modeset = true;
+               }
+               if (full_modeset) {
+                       struct drm_crtc_state *crtc_state =
+                                       drm_atomic_get_crtc_state(state->state, state->crtc);
+                       crtc_state->mode_changed = true;
+                       to_mdp5_plane_state(state)->mode_changed = true;
+               }
+       } else {
+               to_mdp5_plane_state(state)->mode_changed = true;
+       }
 
-               n = DIV_ROUND_UP(fetch_stride * nlines, SMP_BLK_SIZE);
+       return 0;
+}
 
-               /* for hw rev v1.00 */
-               if (mdp5_kms->rev == 0)
-                       n = roundup_pow_of_two(n);
+static void mdp5_plane_atomic_update(struct drm_plane *plane,
+                                    struct drm_plane_state *old_state)
+{
+       struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
+       struct drm_plane_state *state = plane->state;
 
-               DBG("%s[%d]: request %d SMP blocks", mdp5_plane->name, i, n);
-               ret = mdp5_smp_request(mdp5_kms, pipe2client(pipe, i), n);
-               if (ret) {
-                       dev_err(dev->dev, "Could not allocate %d SMP blocks: %d\n",
-                                       n, ret);
-                       return ret;
-               }
+       DBG("%s: update", mdp5_plane->name);
 
-               nblks += n;
+       if (!plane_enabled(state)) {
+               to_mdp5_plane_state(state)->pending = true;
+               mdp5_plane_disable(plane);
+       } else if (to_mdp5_plane_state(state)->mode_changed) {
+               int ret;
+               to_mdp5_plane_state(state)->pending = true;
+               ret = mdp5_plane_mode_set(plane,
+                               state->crtc, state->fb,
+                               state->crtc_x, state->crtc_y,
+                               state->crtc_w, state->crtc_h,
+                               state->src_x,  state->src_y,
+                               state->src_w, state->src_h);
+               /* atomic_check should have ensured that this doesn't fail */
+               WARN_ON(ret < 0);
+       } else {
+               unsigned long flags;
+               spin_lock_irqsave(&mdp5_plane->pipe_lock, flags);
+               set_scanout_locked(plane, state->fb);
+               spin_unlock_irqrestore(&mdp5_plane->pipe_lock, flags);
        }
-
-       /* in success case, return total # of blocks allocated: */
-       return nblks;
 }
 
-static void set_fifo_thresholds(struct drm_plane *plane, int nblks)
+static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs = {
+               .prepare_fb = mdp5_plane_prepare_fb,
+               .cleanup_fb = mdp5_plane_cleanup_fb,
+               .atomic_check = mdp5_plane_atomic_check,
+               .atomic_update = mdp5_plane_atomic_update,
+};
+
+static void set_scanout_locked(struct drm_plane *plane,
+               struct drm_framebuffer *fb)
 {
        struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
        struct mdp5_kms *mdp5_kms = get_kms(plane);
        enum mdp5_pipe pipe = mdp5_plane->pipe;
-       uint32_t val;
 
-       /* 1/4 of SMP pool that is being fetched */
-       val = (nblks * SMP_ENTRIES_PER_BLK) / 4;
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_A(pipe),
+                       MDP5_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) |
+                       MDP5_PIPE_SRC_STRIDE_A_P1(fb->pitches[1]));
 
-       mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_0(pipe), val * 1);
-       mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_1(pipe), val * 2);
-       mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_2(pipe), val * 3);
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_B(pipe),
+                       MDP5_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) |
+                       MDP5_PIPE_SRC_STRIDE_B_P3(fb->pitches[3]));
+
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC0_ADDR(pipe),
+                       msm_framebuffer_iova(fb, mdp5_kms->id, 0));
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC1_ADDR(pipe),
+                       msm_framebuffer_iova(fb, mdp5_kms->id, 1));
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe),
+                       msm_framebuffer_iova(fb, mdp5_kms->id, 2));
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe),
+                       msm_framebuffer_iova(fb, mdp5_kms->id, 4));
 
+       plane->fb = fb;
 }
 
-int mdp5_plane_mode_set(struct drm_plane *plane,
+static int mdp5_plane_mode_set(struct drm_plane *plane,
                struct drm_crtc *crtc, struct drm_framebuffer *fb,
                int crtc_x, int crtc_y,
                unsigned int crtc_w, unsigned int crtc_h,
@@ -225,7 +291,8 @@ int mdp5_plane_mode_set(struct drm_plane *plane,
        uint32_t nplanes, config = 0;
        uint32_t phasex_step = 0, phasey_step = 0;
        uint32_t hdecm = 0, vdecm = 0;
-       int i, nblks;
+       unsigned long flags;
+       int ret;
 
        nplanes = drm_format_num_planes(fb->pixel_format);
 
@@ -243,12 +310,11 @@ int mdp5_plane_mode_set(struct drm_plane *plane,
                        fb->base.id, src_x, src_y, src_w, src_h,
                        crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
 
-       /*
-        * Calculate and request required # of smp blocks:
-        */
-       nblks = request_smp_blocks(plane, fb->pixel_format, nplanes, src_w);
-       if (nblks < 0)
-               return nblks;
+       /* Request some memory from the SMP: */
+       ret = mdp5_smp_request(mdp5_kms->smp,
+                       mdp5_plane->pipe, fb->pixel_format, src_w);
+       if (ret)
+               return ret;
 
        /*
         * Currently we update the hw for allocations/requests immediately,
@@ -256,8 +322,7 @@ int mdp5_plane_mode_set(struct drm_plane *plane,
         * would move into atomic->check_plane_state(), while updating the
         * hw would remain here:
         */
-       for (i = 0; i < pipe2nclients(pipe); i++)
-               mdp5_smp_configure(mdp5_kms, pipe2client(pipe, i));
+       mdp5_smp_configure(mdp5_kms->smp, pipe);
 
        if (src_w != crtc_w) {
                config |= MDP5_PIPE_SCALE_CONFIG_SCALEX_EN;
@@ -269,6 +334,8 @@ int mdp5_plane_mode_set(struct drm_plane *plane,
                /* TODO calc phasey_step, vdecm */
        }
 
+       spin_lock_irqsave(&mdp5_plane->pipe_lock, flags);
+
        mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe),
                        MDP5_PIPE_SRC_IMG_SIZE_WIDTH(src_w) |
                        MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(src_h));
@@ -289,8 +356,6 @@ int mdp5_plane_mode_set(struct drm_plane *plane,
                        MDP5_PIPE_OUT_XY_X(crtc_x) |
                        MDP5_PIPE_OUT_XY_Y(crtc_y));
 
-       mdp5_plane_set_scanout(plane, fb);
-
        format = to_mdp_format(msm_framebuffer_format(fb));
 
        mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe),
@@ -330,22 +395,24 @@ int mdp5_plane_mode_set(struct drm_plane *plane,
                        MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(SCALE_FILTER_NEAREST) |
                        MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(SCALE_FILTER_NEAREST));
 
-       set_fifo_thresholds(plane, nblks);
+       set_scanout_locked(plane, fb);
 
-       /* TODO detach from old crtc (if we had more than one) */
-       mdp5_crtc_attach(crtc, plane);
+       spin_unlock_irqrestore(&mdp5_plane->pipe_lock, flags);
 
-       return 0;
+       return ret;
 }
 
 void mdp5_plane_complete_flip(struct drm_plane *plane)
 {
        struct mdp5_kms *mdp5_kms = get_kms(plane);
-       enum mdp5_pipe pipe = to_mdp5_plane(plane)->pipe;
-       int i;
+       struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
+       enum mdp5_pipe pipe = mdp5_plane->pipe;
+
+       DBG("%s: complete flip", mdp5_plane->name);
 
-       for (i = 0; i < pipe2nclients(pipe); i++)
-               mdp5_smp_commit(mdp5_kms, pipe2client(pipe, i));
+       mdp5_smp_commit(mdp5_kms->smp, pipe);
+
+       to_mdp5_plane_state(plane->state)->pending = false;
 }
 
 enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane)
@@ -354,9 +421,16 @@ enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane)
        return mdp5_plane->pipe;
 }
 
+uint32_t mdp5_plane_get_flush(struct drm_plane *plane)
+{
+       struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
+
+       return mdp5_plane->flush_mask;
+}
+
 /* initialize plane */
 struct drm_plane *mdp5_plane_init(struct drm_device *dev,
-               enum mdp5_pipe pipe, bool private_plane)
+               enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset)
 {
        struct drm_plane *plane = NULL;
        struct mdp5_plane *mdp5_plane;
@@ -377,10 +451,18 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev,
        mdp5_plane->nformats = mdp5_get_formats(pipe, mdp5_plane->formats,
                        ARRAY_SIZE(mdp5_plane->formats));
 
+       mdp5_plane->flush_mask = mdp_ctl_flush_mask_pipe(pipe);
+       mdp5_plane->reg_offset = reg_offset;
+       spin_lock_init(&mdp5_plane->pipe_lock);
+
        type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
-       drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
+       ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
                                 mdp5_plane->formats, mdp5_plane->nformats,
                                 type);
+       if (ret)
+               goto fail;
+
+       drm_plane_helper_add(plane, &mdp5_plane_helper_funcs);
 
        mdp5_plane_install_properties(plane, &plane->base);
 
index 2d0236b963a6f76179c897241cee1ff7bcd034b1..bf551885e0197ed7421f32ab8976b66580e41dd5 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
  * Based on the size of the attached scanout buffer, a certain # of
  * blocks must be allocated to that client out of the shared pool.
  *
- * For each block, it can be either free, or pending/in-use by a
- * client.  The updates happen in three steps:
+ * In some hw, some blocks are statically allocated for certain pipes
+ * and CANNOT be re-allocated (eg: MMB0 and MMB1 both tied to RGB0).
+ *
+ * For each block that can be dynamically allocated, it can be either
+ * free, or pending/in-use by a client. The updates happen in three steps:
  *
  *  1) mdp5_smp_request():
  *     When plane scanout is setup, calculate required number of
  * inuse and pending state of all clients..
  */
 
-static DEFINE_SPINLOCK(smp_lock);
+struct mdp5_smp {
+       struct drm_device *dev;
+
+       int blk_cnt;
+       int blk_size;
+
+       spinlock_t state_lock;
+       mdp5_smp_state_t state; /* to track smp allocation amongst pipes: */
+
+       struct mdp5_client_smp_state client_state[CID_MAX];
+};
 
+static inline
+struct mdp5_kms *get_kms(struct mdp5_smp *smp)
+{
+       struct msm_drm_private *priv = smp->dev->dev_private;
+
+       return to_mdp5_kms(to_mdp_kms(priv->kms));
+}
+
+static inline enum mdp5_client_id pipe2client(enum mdp5_pipe pipe, int plane)
+{
+       WARN_ON(plane >= pipe2nclients(pipe));
+       switch (pipe) {
+       case SSPP_VIG0: return CID_VIG0_Y + plane;
+       case SSPP_VIG1: return CID_VIG1_Y + plane;
+       case SSPP_VIG2: return CID_VIG2_Y + plane;
+       case SSPP_RGB0: return CID_RGB0;
+       case SSPP_RGB1: return CID_RGB1;
+       case SSPP_RGB2: return CID_RGB2;
+       case SSPP_DMA0: return CID_DMA0_Y + plane;
+       case SSPP_DMA1: return CID_DMA1_Y + plane;
+       case SSPP_VIG3: return CID_VIG3_Y + plane;
+       case SSPP_RGB3: return CID_RGB3;
+       default:        return CID_UNUSED;
+       }
+}
 
 /* step #1: update # of blocks pending for the client: */
-int mdp5_smp_request(struct mdp5_kms *mdp5_kms,
+static int smp_request_block(struct mdp5_smp *smp,
                enum mdp5_client_id cid, int nblks)
 {
-       struct mdp5_client_smp_state *ps = &mdp5_kms->smp_client_state[cid];
-       int i, ret, avail, cur_nblks, cnt = mdp5_kms->smp_blk_cnt;
+       struct mdp5_kms *mdp5_kms = get_kms(smp);
+       const struct mdp5_cfg_hw *hw_cfg;
+       struct mdp5_client_smp_state *ps = &smp->client_state[cid];
+       int i, ret, avail, cur_nblks, cnt = smp->blk_cnt;
+       int reserved;
        unsigned long flags;
 
-       spin_lock_irqsave(&smp_lock, flags);
+       hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
+       reserved = hw_cfg->smp.reserved[cid];
+
+       spin_lock_irqsave(&smp->state_lock, flags);
 
-       avail = cnt - bitmap_weight(mdp5_kms->smp_state, cnt);
+       nblks -= reserved;
+       if (reserved)
+               DBG("%d MMBs allocated (%d reserved)", nblks, reserved);
+
+       avail = cnt - bitmap_weight(smp->state, cnt);
        if (nblks > avail) {
+               dev_err(mdp5_kms->dev->dev, "out of blks (req=%d > avail=%d)\n",
+                               nblks, avail);
                ret = -ENOSPC;
                goto fail;
        }
@@ -84,9 +135,9 @@ int mdp5_smp_request(struct mdp5_kms *mdp5_kms,
        if (nblks > cur_nblks) {
                /* grow the existing pending reservation: */
                for (i = cur_nblks; i < nblks; i++) {
-                       int blk = find_first_zero_bit(mdp5_kms->smp_state, cnt);
+                       int blk = find_first_zero_bit(smp->state, cnt);
                        set_bit(blk, ps->pending);
-                       set_bit(blk, mdp5_kms->smp_state);
+                       set_bit(blk, smp->state);
                }
        } else {
                /* shrink the existing pending reservation: */
@@ -98,15 +149,88 @@ int mdp5_smp_request(struct mdp5_kms *mdp5_kms,
        }
 
 fail:
-       spin_unlock_irqrestore(&smp_lock, flags);
+       spin_unlock_irqrestore(&smp->state_lock, flags);
+       return 0;
+}
+
+static void set_fifo_thresholds(struct mdp5_smp *smp,
+               enum mdp5_pipe pipe, int nblks)
+{
+       struct mdp5_kms *mdp5_kms = get_kms(smp);
+       u32 smp_entries_per_blk = smp->blk_size / (128 / BITS_PER_BYTE);
+       u32 val;
+
+       /* 1/4 of SMP pool that is being fetched */
+       val = (nblks * smp_entries_per_blk) / 4;
+
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_0(pipe), val * 1);
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_1(pipe), val * 2);
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_2(pipe), val * 3);
+}
+
+/*
+ * NOTE: looks like if horizontal decimation is used (if we supported that)
+ * then the width used to calculate SMP block requirements is the post-
+ * decimated width.  Ie. SMP buffering sits downstream of decimation (which
+ * presumably happens during the dma from scanout buffer).
+ */
+int mdp5_smp_request(struct mdp5_smp *smp, enum mdp5_pipe pipe, u32 fmt, u32 width)
+{
+       struct mdp5_kms *mdp5_kms = get_kms(smp);
+       struct drm_device *dev = mdp5_kms->dev;
+       int rev = mdp5_cfg_get_hw_rev(mdp5_kms->cfg);
+       int i, hsub, nplanes, nlines, nblks, ret;
+
+       nplanes = drm_format_num_planes(fmt);
+       hsub = drm_format_horz_chroma_subsampling(fmt);
+
+       /* different if BWC (compressed framebuffer?) enabled: */
+       nlines = 2;
+
+       for (i = 0, nblks = 0; i < nplanes; i++) {
+               int n, fetch_stride, cpp;
+
+               cpp = drm_format_plane_cpp(fmt, i);
+               fetch_stride = width * cpp / (i ? hsub : 1);
+
+               n = DIV_ROUND_UP(fetch_stride * nlines, smp->blk_size);
+
+               /* for hw rev v1.00 */
+               if (rev == 0)
+                       n = roundup_pow_of_two(n);
+
+               DBG("%s[%d]: request %d SMP blocks", pipe2name(pipe), i, n);
+               ret = smp_request_block(smp, pipe2client(pipe, i), n);
+               if (ret) {
+                       dev_err(dev->dev, "Cannot allocate %d SMP blocks: %d\n",
+                                       n, ret);
+                       return ret;
+               }
+
+               nblks += n;
+       }
+
+       set_fifo_thresholds(smp, pipe, nblks);
+
        return 0;
 }
 
-static void update_smp_state(struct mdp5_kms *mdp5_kms,
+/* Release SMP blocks for all clients of the pipe */
+void mdp5_smp_release(struct mdp5_smp *smp, enum mdp5_pipe pipe)
+{
+       int i, nblks;
+
+       for (i = 0, nblks = 0; i < pipe2nclients(pipe); i++)
+               smp_request_block(smp, pipe2client(pipe, i), 0);
+       set_fifo_thresholds(smp, pipe, 0);
+}
+
+static void update_smp_state(struct mdp5_smp *smp,
                enum mdp5_client_id cid, mdp5_smp_state_t *assigned)
 {
-       int cnt = mdp5_kms->smp_blk_cnt;
-       uint32_t blk, val;
+       struct mdp5_kms *mdp5_kms = get_kms(smp);
+       int cnt = smp->blk_cnt;
+       u32 blk, val;
 
        for_each_set_bit(blk, *assigned, cnt) {
                int idx = blk / 3;
@@ -135,39 +259,80 @@ static void update_smp_state(struct mdp5_kms *mdp5_kms,
 }
 
 /* step #2: configure hw for union(pending, inuse): */
-void mdp5_smp_configure(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid)
+void mdp5_smp_configure(struct mdp5_smp *smp, enum mdp5_pipe pipe)
 {
-       struct mdp5_client_smp_state *ps = &mdp5_kms->smp_client_state[cid];
-       int cnt = mdp5_kms->smp_blk_cnt;
+       int cnt = smp->blk_cnt;
        mdp5_smp_state_t assigned;
+       int i;
 
-       bitmap_or(assigned, ps->inuse, ps->pending, cnt);
-       update_smp_state(mdp5_kms, cid, &assigned);
+       for (i = 0; i < pipe2nclients(pipe); i++) {
+               enum mdp5_client_id cid = pipe2client(pipe, i);
+               struct mdp5_client_smp_state *ps = &smp->client_state[cid];
+
+               bitmap_or(assigned, ps->inuse, ps->pending, cnt);
+               update_smp_state(smp, cid, &assigned);
+       }
 }
 
 /* step #3: after vblank, copy pending -> inuse: */
-void mdp5_smp_commit(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid)
+void mdp5_smp_commit(struct mdp5_smp *smp, enum mdp5_pipe pipe)
 {
-       struct mdp5_client_smp_state *ps = &mdp5_kms->smp_client_state[cid];
-       int cnt = mdp5_kms->smp_blk_cnt;
+       int cnt = smp->blk_cnt;
        mdp5_smp_state_t released;
+       int i;
+
+       for (i = 0; i < pipe2nclients(pipe); i++) {
+               enum mdp5_client_id cid = pipe2client(pipe, i);
+               struct mdp5_client_smp_state *ps = &smp->client_state[cid];
+
+               /*
+                * Figure out if there are any blocks we where previously
+                * using, which can be released and made available to other
+                * clients:
+                */
+               if (bitmap_andnot(released, ps->inuse, ps->pending, cnt)) {
+                       unsigned long flags;
+
+                       spin_lock_irqsave(&smp->state_lock, flags);
+                       /* clear released blocks: */
+                       bitmap_andnot(smp->state, smp->state, released, cnt);
+                       spin_unlock_irqrestore(&smp->state_lock, flags);
 
-       /*
-        * Figure out if there are any blocks we where previously
-        * using, which can be released and made available to other
-        * clients:
-        */
-       if (bitmap_andnot(released, ps->inuse, ps->pending, cnt)) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&smp_lock, flags);
-               /* clear released blocks: */
-               bitmap_andnot(mdp5_kms->smp_state, mdp5_kms->smp_state,
-                               released, cnt);
-               spin_unlock_irqrestore(&smp_lock, flags);
-
-               update_smp_state(mdp5_kms, CID_UNUSED, &released);
+                       update_smp_state(smp, CID_UNUSED, &released);
+               }
+
+               bitmap_copy(ps->inuse, ps->pending, cnt);
        }
+}
+
+void mdp5_smp_destroy(struct mdp5_smp *smp)
+{
+       kfree(smp);
+}
+
+struct mdp5_smp *mdp5_smp_init(struct drm_device *dev, const struct mdp5_smp_block *cfg)
+{
+       struct mdp5_smp *smp = NULL;
+       int ret;
+
+       smp = kzalloc(sizeof(*smp), GFP_KERNEL);
+       if (unlikely(!smp)) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       smp->dev = dev;
+       smp->blk_cnt = cfg->mmb_count;
+       smp->blk_size = cfg->mmb_size;
+
+       /* statically tied MMBs cannot be re-allocated: */
+       bitmap_copy(smp->state, cfg->reserved_state, smp->blk_cnt);
+       spin_lock_init(&smp->state_lock);
+
+       return smp;
+fail:
+       if (smp)
+               mdp5_smp_destroy(smp);
 
-       bitmap_copy(ps->inuse, ps->pending, cnt);
+       return ERR_PTR(ret);
 }
index 0ab739e1a1dd59ccaf0e4bde59dc0a790a469616..e47179f635852a2f6ee546378200ce0a54a64499 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
 
 #include "msm_drv.h"
 
-#define MAX_SMP_BLOCKS  22
-#define SMP_BLK_SIZE    4096
-#define SMP_ENTRIES_PER_BLK (SMP_BLK_SIZE / 16)
-
-typedef DECLARE_BITMAP(mdp5_smp_state_t, MAX_SMP_BLOCKS);
-
 struct mdp5_client_smp_state {
        mdp5_smp_state_t inuse;
        mdp5_smp_state_t pending;
 };
 
 struct mdp5_kms;
+struct mdp5_smp;
+
+/*
+ * SMP module prototypes:
+ * mdp5_smp_init() returns a SMP @handler,
+ * which is then used to call the other mdp5_smp_*(handler, ...) functions.
+ */
 
-int mdp5_smp_request(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid, int nblks);
-void mdp5_smp_configure(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid);
-void mdp5_smp_commit(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid);
+struct mdp5_smp *mdp5_smp_init(struct drm_device *dev, const struct mdp5_smp_block *cfg);
+void  mdp5_smp_destroy(struct mdp5_smp *smp);
 
+int  mdp5_smp_request(struct mdp5_smp *smp, enum mdp5_pipe pipe, u32 fmt, u32 width);
+void mdp5_smp_configure(struct mdp5_smp *smp, enum mdp5_pipe pipe);
+void mdp5_smp_commit(struct mdp5_smp *smp, enum mdp5_pipe pipe);
+void mdp5_smp_release(struct mdp5_smp *smp, enum mdp5_pipe pipe);
 
 #endif /* __MDP5_SMP_H__ */
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
new file mode 100644 (file)
index 0000000..f0de412
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2014 Red Hat
+ * Author: Rob Clark <robdclark@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "msm_drv.h"
+#include "msm_kms.h"
+#include "msm_gem.h"
+
+struct msm_commit {
+       struct drm_atomic_state *state;
+       uint32_t fence;
+       struct msm_fence_cb fence_cb;
+};
+
+static void fence_cb(struct msm_fence_cb *cb);
+
+static struct msm_commit *new_commit(struct drm_atomic_state *state)
+{
+       struct msm_commit *c = kzalloc(sizeof(*c), GFP_KERNEL);
+
+       if (!c)
+               return NULL;
+
+       c->state = state;
+       /* TODO we might need a way to indicate to run the cb on a
+        * different wq so wait_for_vblanks() doesn't block retiring
+        * bo's..
+        */
+       INIT_FENCE_CB(&c->fence_cb, fence_cb);
+
+       return c;
+}
+
+/* The (potentially) asynchronous part of the commit.  At this point
+ * nothing can fail short of armageddon.
+ */
+static void complete_commit(struct msm_commit *c)
+{
+       struct drm_atomic_state *state = c->state;
+       struct drm_device *dev = state->dev;
+
+       drm_atomic_helper_commit_pre_planes(dev, state);
+
+       drm_atomic_helper_commit_planes(dev, state);
+
+       drm_atomic_helper_commit_post_planes(dev, state);
+
+       drm_atomic_helper_wait_for_vblanks(dev, state);
+
+       drm_atomic_helper_cleanup_planes(dev, state);
+
+       drm_atomic_state_free(state);
+
+       kfree(c);
+}
+
+static void fence_cb(struct msm_fence_cb *cb)
+{
+       struct msm_commit *c =
+                       container_of(cb, struct msm_commit, fence_cb);
+       complete_commit(c);
+}
+
+static void add_fb(struct msm_commit *c, struct drm_framebuffer *fb)
+{
+       struct drm_gem_object *obj = msm_framebuffer_bo(fb, 0);
+       c->fence = max(c->fence, msm_gem_fence(to_msm_bo(obj), MSM_PREP_READ));
+}
+
+
+/**
+ * drm_atomic_helper_commit - commit validated state object
+ * @dev: DRM device
+ * @state: the driver state object
+ * @async: asynchronous commit
+ *
+ * This function commits a with drm_atomic_helper_check() pre-validated state
+ * object. This can still fail when e.g. the framebuffer reservation fails. For
+ * now this doesn't implement asynchronous commits.
+ *
+ * RETURNS
+ * Zero for success or -errno.
+ */
+int msm_atomic_commit(struct drm_device *dev,
+               struct drm_atomic_state *state, bool async)
+{
+       struct msm_commit *c;
+       int nplanes = dev->mode_config.num_total_plane;
+       int i, ret;
+
+       ret = drm_atomic_helper_prepare_planes(dev, state);
+       if (ret)
+               return ret;
+
+       c = new_commit(state);
+
+       /*
+        * Figure out what fence to wait for:
+        */
+       for (i = 0; i < nplanes; i++) {
+               struct drm_plane *plane = state->planes[i];
+               struct drm_plane_state *new_state = state->plane_states[i];
+
+               if (!plane)
+                       continue;
+
+               if ((plane->state->fb != new_state->fb) && new_state->fb)
+                       add_fb(c, new_state->fb);
+       }
+
+       /*
+        * This is the point of no return - everything below never fails except
+        * when the hw goes bonghits. Which means we can commit the new state on
+        * the software side now.
+        */
+
+       drm_atomic_helper_swap_state(dev, state);
+
+       /*
+        * Everything below can be run asynchronously without the need to grab
+        * any modeset locks at all under one conditions: It must be guaranteed
+        * that the asynchronous work has either been cancelled (if the driver
+        * supports it, which at least requires that the framebuffers get
+        * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
+        * before the new state gets committed on the software side with
+        * drm_atomic_helper_swap_state().
+        *
+        * This scheme allows new atomic state updates to be prepared and
+        * checked in parallel to the asynchronous completion of the previous
+        * update. Which is important since compositors need to figure out the
+        * composition of the next frame right after having submitted the
+        * current layout.
+        */
+
+       if (async) {
+               msm_queue_fence_cb(dev, &c->fence_cb, c->fence);
+               return 0;
+       }
+
+       ret = msm_wait_fence_interruptable(dev, c->fence, NULL);
+       if (ret) {
+               WARN_ON(ret);  // TODO unswap state back?  or??
+               kfree(c);
+               return ret;
+       }
+
+       complete_commit(c);
+
+       return 0;
+}
index b67ef59851250f6c442cf1dedfa0a88db5230ce9..d3b791b7ddef014e35b76ec43db3be1f8f576cf2 100644 (file)
@@ -29,6 +29,8 @@ static void msm_fb_output_poll_changed(struct drm_device *dev)
 static const struct drm_mode_config_funcs mode_config_funcs = {
        .fb_create = msm_framebuffer_create,
        .output_poll_changed = msm_fb_output_poll_changed,
+       .atomic_check = drm_atomic_helper_check,
+       .atomic_commit = msm_atomic_commit,
 };
 
 int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu)
@@ -294,6 +296,8 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
                goto fail;
        }
 
+       drm_mode_config_reset(dev);
+
 #ifdef CONFIG_DRM_MSM_FBDEV
        priv->fbdev = msm_fbdev_init(dev);
 #endif
@@ -619,6 +623,26 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
        return ret;
 }
 
+int msm_queue_fence_cb(struct drm_device *dev,
+               struct msm_fence_cb *cb, uint32_t fence)
+{
+       struct msm_drm_private *priv = dev->dev_private;
+       int ret = 0;
+
+       mutex_lock(&dev->struct_mutex);
+       if (!list_empty(&cb->work.entry)) {
+               ret = -EINVAL;
+       } else if (fence > priv->completed_fence) {
+               cb->fence = fence;
+               list_add_tail(&cb->work.entry, &priv->fence_cbs);
+       } else {
+               queue_work(priv->wq, &cb->work);
+       }
+       mutex_unlock(&dev->struct_mutex);
+
+       return ret;
+}
+
 /* called from workqueue */
 void msm_update_fence(struct drm_device *dev, uint32_t fence)
 {
@@ -832,6 +856,7 @@ static struct drm_driver msm_driver = {
        .gem_prime_import_sg_table = msm_gem_prime_import_sg_table,
        .gem_prime_vmap     = msm_gem_prime_vmap,
        .gem_prime_vunmap   = msm_gem_prime_vunmap,
+       .gem_prime_mmap     = msm_gem_prime_mmap,
 #ifdef CONFIG_DEBUG_FS
        .debugfs_init       = msm_debugfs_init,
        .debugfs_cleanup    = msm_debugfs_cleanup,
index 67f9d0a2332c28b9983d7fe29000f907ffcd87f5..136303818436726004b2f294c6c90d69ccdd2f05 100644 (file)
 #include <linux/types.h>
 #include <asm/sizes.h>
 
-
-#if defined(CONFIG_COMPILE_TEST) && !defined(CONFIG_ARCH_QCOM)
-/* stubs we need for compile-test: */
-static inline struct device *msm_iommu_get_ctx(const char *ctx_name)
-{
-       return NULL;
-}
-#endif
-
 #ifndef CONFIG_OF
 #include <mach/board.h>
 #include <mach/socinfo.h>
@@ -48,7 +39,10 @@ static inline struct device *msm_iommu_get_ctx(const char *ctx_name)
 #endif
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/msm_drm.h>
 #include <drm/drm_gem.h>
@@ -75,7 +69,12 @@ struct msm_drm_private {
        struct msm_kms *kms;
 
        /* subordinate devices, if present: */
-       struct platform_device *hdmi_pdev, *gpu_pdev;
+       struct platform_device *gpu_pdev;
+
+       /* possibly this should be in the kms component, but it is
+        * shared by both mdp4 and mdp5..
+        */
+       struct hdmi *hdmi;
 
        /* when we have more than one 'msm_gpu' these need to be an array: */
        struct msm_gpu *gpu;
@@ -145,21 +144,29 @@ void __msm_fence_worker(struct work_struct *work);
                (_cb)->func = _func;                         \
        } while (0)
 
+int msm_atomic_commit(struct drm_device *dev,
+               struct drm_atomic_state *state, bool async);
+
 int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu);
 
 int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
                struct timespec *timeout);
+int msm_queue_fence_cb(struct drm_device *dev,
+               struct msm_fence_cb *cb, uint32_t fence);
 void msm_update_fence(struct drm_device *dev, uint32_t fence);
 
 int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
                struct drm_file *file);
 
+int msm_gem_mmap_obj(struct drm_gem_object *obj,
+                       struct vm_area_struct *vma);
 int msm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
 int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
 uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj);
 int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id,
                uint32_t *iova);
 int msm_gem_get_iova(struct drm_gem_object *obj, int id, uint32_t *iova);
+uint32_t msm_gem_iova(struct drm_gem_object *obj, int id);
 struct page **msm_gem_get_pages(struct drm_gem_object *obj);
 void msm_gem_put_pages(struct drm_gem_object *obj);
 void msm_gem_put_iova(struct drm_gem_object *obj, int id);
@@ -170,6 +177,7 @@ int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
 struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj);
 void *msm_gem_prime_vmap(struct drm_gem_object *obj);
 void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
+int msm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
 struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev,
                struct dma_buf_attachment *attach, struct sg_table *sg);
 int msm_gem_prime_pin(struct drm_gem_object *obj);
@@ -192,6 +200,9 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
 struct drm_gem_object *msm_gem_import(struct drm_device *dev,
                uint32_t size, struct sg_table *sgt);
 
+int msm_framebuffer_prepare(struct drm_framebuffer *fb, int id);
+void msm_framebuffer_cleanup(struct drm_framebuffer *fb, int id);
+uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb, int id, int plane);
 struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane);
 const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb);
 struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
@@ -202,8 +213,8 @@ struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
 struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev);
 
 struct hdmi;
-struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder);
-irqreturn_t hdmi_irq(int irq, void *dev_id);
+int hdmi_modeset_init(struct hdmi *hdmi, struct drm_device *dev,
+               struct drm_encoder *encoder);
 void __init hdmi_register(void);
 void __exit hdmi_unregister(void);
 
index 81bafdf19ab39fc32428e6f5be692c597a6a8276..84dec161d8360522081826e049a7cbd7b7995101 100644 (file)
@@ -24,7 +24,7 @@
 struct msm_framebuffer {
        struct drm_framebuffer base;
        const struct msm_format *format;
-       struct drm_gem_object *planes[2];
+       struct drm_gem_object *planes[3];
 };
 #define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base)
 
@@ -87,6 +87,44 @@ void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
 }
 #endif
 
+/* prepare/pin all the fb's bo's for scanout.  Note that it is not valid
+ * to prepare an fb more multiple different initiator 'id's.  But that
+ * should be fine, since only the scanout (mdpN) side of things needs
+ * this, the gpu doesn't care about fb's.
+ */
+int msm_framebuffer_prepare(struct drm_framebuffer *fb, int id)
+{
+       struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
+       int ret, i, n = drm_format_num_planes(fb->pixel_format);
+       uint32_t iova;
+
+       for (i = 0; i < n; i++) {
+               ret = msm_gem_get_iova(msm_fb->planes[i], id, &iova);
+               DBG("FB[%u]: iova[%d]: %08x (%d)", fb->base.id, i, iova, ret);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+void msm_framebuffer_cleanup(struct drm_framebuffer *fb, int id)
+{
+       struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
+       int i, n = drm_format_num_planes(fb->pixel_format);
+
+       for (i = 0; i < n; i++)
+               msm_gem_put_iova(msm_fb->planes[i], id);
+}
+
+uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb, int id, int plane)
+{
+       struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
+       if (!msm_fb->planes[plane])
+               return 0;
+       return msm_gem_iova(msm_fb->planes[plane], id);
+}
+
 struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane)
 {
        struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
@@ -166,6 +204,11 @@ struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
 
        msm_fb->format = format;
 
+       if (n > ARRAY_SIZE(msm_fb->planes)) {
+               ret = -EINVAL;
+               goto fail;
+       }
+
        for (i = 0; i < n; i++) {
                unsigned int width = mode_cmd->width / (i ? hsub : 1);
                unsigned int height = mode_cmd->height / (i ? vsub : 1);
index ab5bfd2d0ebf2e29897fa56e1df2c77c0f47aeb8..94d55e526b4e0732cba7fcf45a2ce725c2433637 100644 (file)
@@ -93,9 +93,6 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
        uint32_t paddr;
        int ret, size;
 
-       sizes->surface_bpp = 32;
-       sizes->surface_depth = 24;
-
        DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width,
                        sizes->surface_height, sizes->surface_bpp,
                        sizes->fb_width, sizes->fb_height);
index 4b1b82adabdeaa504cd63ca290ff37f6acc223de..4a6f0e49d5b5f0709d586e3dcf4e271a0c99c0f5 100644 (file)
@@ -309,6 +309,7 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id,
        return ret;
 }
 
+/* get iova, taking a reference.  Should have a matching put */
 int msm_gem_get_iova(struct drm_gem_object *obj, int id, uint32_t *iova)
 {
        struct msm_gem_object *msm_obj = to_msm_bo(obj);
@@ -328,6 +329,16 @@ int msm_gem_get_iova(struct drm_gem_object *obj, int id, uint32_t *iova)
        return ret;
 }
 
+/* get iova without taking a reference, used in places where you have
+ * already done a 'msm_gem_get_iova()'.
+ */
+uint32_t msm_gem_iova(struct drm_gem_object *obj, int id)
+{
+       struct msm_gem_object *msm_obj = to_msm_bo(obj);
+       WARN_ON(!msm_obj->domain[id].iova);
+       return msm_obj->domain[id].iova;
+}
+
 void msm_gem_put_iova(struct drm_gem_object *obj, int id)
 {
        // XXX TODO ..
@@ -397,23 +408,10 @@ void *msm_gem_vaddr(struct drm_gem_object *obj)
 int msm_gem_queue_inactive_cb(struct drm_gem_object *obj,
                struct msm_fence_cb *cb)
 {
-       struct drm_device *dev = obj->dev;
-       struct msm_drm_private *priv = dev->dev_private;
        struct msm_gem_object *msm_obj = to_msm_bo(obj);
-       int ret = 0;
-
-       mutex_lock(&dev->struct_mutex);
-       if (!list_empty(&cb->work.entry)) {
-               ret = -EINVAL;
-       } else if (is_active(msm_obj)) {
-               cb->fence = max(msm_obj->read_fence, msm_obj->write_fence);
-               list_add_tail(&cb->work.entry, &priv->fence_cbs);
-       } else {
-               queue_work(priv->wq, &cb->work);
-       }
-       mutex_unlock(&dev->struct_mutex);
-
-       return ret;
+       uint32_t fence = msm_gem_fence(msm_obj,
+                       MSM_PREP_READ | MSM_PREP_WRITE);
+       return msm_queue_fence_cb(obj->dev, cb, fence);
 }
 
 void msm_gem_move_to_active(struct drm_gem_object *obj,
@@ -452,12 +450,8 @@ int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
        int ret = 0;
 
        if (is_active(msm_obj)) {
-               uint32_t fence = 0;
+               uint32_t fence = msm_gem_fence(msm_obj, op);
 
-               if (op & MSM_PREP_READ)
-                       fence = msm_obj->write_fence;
-               if (op & MSM_PREP_WRITE)
-                       fence = max(fence, msm_obj->read_fence);
                if (op & MSM_PREP_NOSYNC)
                        timeout = NULL;
 
@@ -525,13 +519,11 @@ void msm_gem_free_object(struct drm_gem_object *obj)
        for (id = 0; id < ARRAY_SIZE(msm_obj->domain); id++) {
                struct msm_mmu *mmu = priv->mmus[id];
                if (mmu && msm_obj->domain[id].iova) {
-                       uint32_t offset = (uint32_t)mmap_offset(obj);
+                       uint32_t offset = msm_obj->domain[id].iova;
                        mmu->funcs->unmap(mmu, offset, msm_obj->sgt, obj->size);
                }
        }
 
-       drm_gem_free_mmap_offset(obj);
-
        if (obj->import_attach) {
                if (msm_obj->vaddr)
                        dma_buf_vunmap(obj->import_attach->dmabuf, msm_obj->vaddr);
index bfb052688f8ea01a7852bb748cc508c40d1311d3..8fbbd0594c46604e107d19a3fbbe59a735d2375d 100644 (file)
@@ -70,6 +70,19 @@ static inline bool is_active(struct msm_gem_object *msm_obj)
        return msm_obj->gpu != NULL;
 }
 
+static inline uint32_t msm_gem_fence(struct msm_gem_object *msm_obj,
+               uint32_t op)
+{
+       uint32_t fence = 0;
+
+       if (op & MSM_PREP_READ)
+               fence = msm_obj->write_fence;
+       if (op & MSM_PREP_WRITE)
+               fence = max(fence, msm_obj->read_fence);
+
+       return fence;
+}
+
 #define MAX_CMDS 4
 
 /* Created per submit-ioctl, to track bo's and cmdstream bufs, etc,
index ad772fe36115f69c47aaca1f1caa2c2356a8bd01..dd7a7ab603e2c202ea297575fab0aba003234f5b 100644 (file)
@@ -37,6 +37,19 @@ void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
        /* TODO msm_gem_vunmap() */
 }
 
+int msm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
+{
+       int ret;
+
+       mutex_lock(&obj->dev->struct_mutex);
+       ret = drm_gem_mmap_obj(obj, obj->size, vma);
+       mutex_unlock(&obj->dev->struct_mutex);
+       if (ret < 0)
+               return ret;
+
+       return msm_gem_mmap_obj(vma->vm_private_data, vma);
+}
+
 struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev,
                struct dma_buf_attachment *attach, struct sg_table *sg)
 {
index 12c24c8abf7f54ab8c94af874b6220a931053d45..6461e3565afe2b1f5c76fbbeca06e594fad0b657 100644 (file)
@@ -41,17 +41,28 @@ nouveau-y += core/subdev/bios/extdev.o
 nouveau-y += core/subdev/bios/fan.o
 nouveau-y += core/subdev/bios/gpio.o
 nouveau-y += core/subdev/bios/i2c.o
+nouveau-y += core/subdev/bios/image.o
 nouveau-y += core/subdev/bios/init.o
 nouveau-y += core/subdev/bios/mxm.o
+nouveau-y += core/subdev/bios/npde.o
+nouveau-y += core/subdev/bios/pcir.o
 nouveau-y += core/subdev/bios/perf.o
 nouveau-y += core/subdev/bios/pll.o
+nouveau-y += core/subdev/bios/pmu.o
 nouveau-y += core/subdev/bios/ramcfg.o
 nouveau-y += core/subdev/bios/rammap.o
+nouveau-y += core/subdev/bios/shadow.o
+nouveau-y += core/subdev/bios/shadowacpi.o
+nouveau-y += core/subdev/bios/shadowof.o
+nouveau-y += core/subdev/bios/shadowpci.o
+nouveau-y += core/subdev/bios/shadowramin.o
+nouveau-y += core/subdev/bios/shadowrom.o
 nouveau-y += core/subdev/bios/timing.o
 nouveau-y += core/subdev/bios/therm.o
 nouveau-y += core/subdev/bios/vmap.o
 nouveau-y += core/subdev/bios/volt.o
 nouveau-y += core/subdev/bios/xpio.o
+nouveau-y += core/subdev/bios/M0203.o
 nouveau-y += core/subdev/bios/M0205.o
 nouveau-y += core/subdev/bios/M0209.o
 nouveau-y += core/subdev/bios/P0260.o
@@ -86,6 +97,7 @@ nouveau-y += core/subdev/devinit/nva3.o
 nouveau-y += core/subdev/devinit/nvaf.o
 nouveau-y += core/subdev/devinit/nvc0.o
 nouveau-y += core/subdev/devinit/gm107.o
+nouveau-y += core/subdev/devinit/gm204.o
 nouveau-y += core/subdev/fb/base.o
 nouveau-y += core/subdev/fb/nv04.o
 nouveau-y += core/subdev/fb/nv10.o
@@ -129,6 +141,7 @@ nouveau-y += core/subdev/fb/ramgk20a.o
 nouveau-y += core/subdev/fb/ramgm107.o
 nouveau-y += core/subdev/fb/sddr2.o
 nouveau-y += core/subdev/fb/sddr3.o
+nouveau-y += core/subdev/fb/gddr3.o
 nouveau-y += core/subdev/fb/gddr5.o
 nouveau-y += core/subdev/fuse/base.o
 nouveau-y += core/subdev/fuse/g80.o
@@ -147,6 +160,7 @@ nouveau-y += core/subdev/i2c/bit.o
 nouveau-y += core/subdev/i2c/pad.o
 nouveau-y += core/subdev/i2c/padnv04.o
 nouveau-y += core/subdev/i2c/padnv94.o
+nouveau-y += core/subdev/i2c/padgm204.o
 nouveau-y += core/subdev/i2c/nv04.o
 nouveau-y += core/subdev/i2c/nv4e.o
 nouveau-y += core/subdev/i2c/nv50.o
@@ -154,6 +168,7 @@ nouveau-y += core/subdev/i2c/nv94.o
 nouveau-y += core/subdev/i2c/nvd0.o
 nouveau-y += core/subdev/i2c/gf117.o
 nouveau-y += core/subdev/i2c/nve0.o
+nouveau-y += core/subdev/i2c/gm204.o
 nouveau-y += core/subdev/ibus/nvc0.o
 nouveau-y += core/subdev/ibus/nve0.o
 nouveau-y += core/subdev/ibus/gk20a.o
@@ -211,6 +226,7 @@ nouveau-y += core/subdev/vm/nvc0.o
 nouveau-y += core/subdev/volt/base.o
 nouveau-y += core/subdev/volt/gpio.o
 nouveau-y += core/subdev/volt/nv40.o
+nouveau-y += core/subdev/volt/gk20a.o
 
 nouveau-y += core/engine/falcon.o
 nouveau-y += core/engine/xtensa.o
@@ -254,6 +270,7 @@ nouveau-y += core/engine/disp/nvd0.o
 nouveau-y += core/engine/disp/nve0.o
 nouveau-y += core/engine/disp/nvf0.o
 nouveau-y += core/engine/disp/gm107.o
+nouveau-y += core/engine/disp/gm204.o
 nouveau-y += core/engine/disp/dacnv50.o
 nouveau-y += core/engine/disp/dport.o
 nouveau-y += core/engine/disp/hdanva3.o
@@ -266,6 +283,7 @@ nouveau-y += core/engine/disp/piornv50.o
 nouveau-y += core/engine/disp/sornv50.o
 nouveau-y += core/engine/disp/sornv94.o
 nouveau-y += core/engine/disp/sornvd0.o
+nouveau-y += core/engine/disp/sorgm204.o
 nouveau-y += core/engine/disp/vga.o
 nouveau-y += core/engine/fifo/base.o
 nouveau-y += core/engine/fifo/nv04.o
index a490b805d7e321e0db2715ed979388e657b9f0e5..13f816cb08bd6b69039e74bc9eab32ab9df567c9 100644 (file)
@@ -222,116 +222,3 @@ nouveau_handle_put(struct nouveau_handle *handle)
        if (handle)
                nouveau_namedb_put(handle);
 }
-
-int
-nouveau_handle_new(struct nouveau_object *client, u32 _parent, u32 _handle,
-                  u16 _oclass, void *data, u32 size,
-                  struct nouveau_object **pobject)
-{
-       struct nouveau_object *parent = NULL;
-       struct nouveau_object *engctx = NULL;
-       struct nouveau_object *object = NULL;
-       struct nouveau_object *engine;
-       struct nouveau_oclass *oclass;
-       struct nouveau_handle *handle;
-       int ret;
-
-       /* lookup parent object and ensure it *is* a parent */
-       parent = nouveau_handle_ref(client, _parent);
-       if (!parent) {
-               nv_error(client, "parent 0x%08x not found\n", _parent);
-               return -ENOENT;
-       }
-
-       if (!nv_iclass(parent, NV_PARENT_CLASS)) {
-               nv_error(parent, "cannot have children\n");
-               ret = -EINVAL;
-               goto fail_class;
-       }
-
-       /* check that parent supports the requested subclass */
-       ret = nouveau_parent_sclass(parent, _oclass, &engine, &oclass);
-       if (ret) {
-               nv_debug(parent, "illegal class 0x%04x\n", _oclass);
-               goto fail_class;
-       }
-
-       /* make sure engine init has been completed *before* any objects
-        * it controls are created - the constructors may depend on
-        * state calculated at init (ie. default context construction)
-        */
-       if (engine) {
-               ret = nouveau_object_inc(engine);
-               if (ret)
-                       goto fail_class;
-       }
-
-       /* if engine requires it, create a context object to insert
-        * between the parent and its children (eg. PGRAPH context)
-        */
-       if (engine && nv_engine(engine)->cclass) {
-               ret = nouveau_object_ctor(parent, engine,
-                                         nv_engine(engine)->cclass,
-                                         data, size, &engctx);
-               if (ret)
-                       goto fail_engctx;
-       } else {
-               nouveau_object_ref(parent, &engctx);
-       }
-
-       /* finally, create new object and bind it to its handle */
-       ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object);
-       *pobject = object;
-       if (ret)
-               goto fail_ctor;
-
-       ret = nouveau_object_inc(object);
-       if (ret)
-               goto fail_init;
-
-       ret = nouveau_handle_create(parent, _parent, _handle, object, &handle);
-       if (ret)
-               goto fail_handle;
-
-       ret = nouveau_handle_init(handle);
-       if (ret)
-               nouveau_handle_destroy(handle);
-
-fail_handle:
-       nouveau_object_dec(object, false);
-fail_init:
-       nouveau_object_ref(NULL, &object);
-fail_ctor:
-       nouveau_object_ref(NULL, &engctx);
-fail_engctx:
-       if (engine)
-               nouveau_object_dec(engine, false);
-fail_class:
-       nouveau_object_ref(NULL, &parent);
-       return ret;
-}
-
-int
-nouveau_handle_del(struct nouveau_object *client, u32 _parent, u32 _handle)
-{
-       struct nouveau_object *parent = NULL;
-       struct nouveau_object *namedb = NULL;
-       struct nouveau_handle *handle = NULL;
-
-       parent = nouveau_handle_ref(client, _parent);
-       if (!parent)
-               return -ENOENT;
-
-       namedb = nv_pclass(parent, NV_NAMEDB_CLASS);
-       if (namedb) {
-               handle = nouveau_namedb_get(nv_namedb(namedb), _handle);
-               if (handle) {
-                       nouveau_namedb_put(handle);
-                       nouveau_handle_fini(handle, false);
-                       nouveau_handle_destroy(handle);
-               }
-       }
-
-       nouveau_object_ref(NULL, &parent);
-       return handle ? 0 : -EINVAL;
-}
index 0ef5a5713182bc5e8d05a45ad8670672286d945b..137e0b0faeae0d1b76ad9e5359c2eef9b66e0642 100644 (file)
@@ -29,6 +29,7 @@
 #include <nvif/unpack.h>
 #include <nvif/class.h>
 
+#include <subdev/bios.h>
 #include <subdev/fb.h>
 #include <subdev/instmem.h>
 
@@ -138,7 +139,7 @@ nouveau_devobj_info(struct nouveau_object *object, void *data, u32 size)
        }
 
        args->v0.chipset  = device->chipset;
-       args->v0.revision = device->chipset >= 0x10 ? nv_rd32(device, 0) : 0x00;
+       args->v0.revision = device->chiprev;
        if (pfb)  args->v0.ram_size = args->v0.ram_user = pfb->ram->size;
        else      args->v0.ram_size = args->v0.ram_user = 0;
        if (imem) args->v0.ram_user = args->v0.ram_user - imem->reserved;
@@ -222,6 +223,7 @@ static const u64 disable_map[] = {
        [NVDEV_SUBDEV_VOLT]     = NV_DEVICE_V0_DISABLE_CORE,
        [NVDEV_SUBDEV_THERM]    = NV_DEVICE_V0_DISABLE_CORE,
        [NVDEV_SUBDEV_PWR]      = NV_DEVICE_V0_DISABLE_CORE,
+       [NVDEV_SUBDEV_FUSE]     = NV_DEVICE_V0_DISABLE_CORE,
        [NVDEV_ENGINE_DMAOBJ]   = NV_DEVICE_V0_DISABLE_CORE,
        [NVDEV_ENGINE_PERFMON]  = NV_DEVICE_V0_DISABLE_CORE,
        [NVDEV_ENGINE_FIFO]     = NV_DEVICE_V0_DISABLE_FIFO,
@@ -235,6 +237,7 @@ static const u64 disable_map[] = {
        [NVDEV_ENGINE_PPP]      = NV_DEVICE_V0_DISABLE_PPP,
        [NVDEV_ENGINE_COPY0]    = NV_DEVICE_V0_DISABLE_COPY0,
        [NVDEV_ENGINE_COPY1]    = NV_DEVICE_V0_DISABLE_COPY1,
+       [NVDEV_ENGINE_COPY2]    = NV_DEVICE_V0_DISABLE_COPY1,
        [NVDEV_ENGINE_VIC]      = NV_DEVICE_V0_DISABLE_VIC,
        [NVDEV_ENGINE_VENC]     = NV_DEVICE_V0_DISABLE_VENC,
        [NVDEV_ENGINE_DISP]     = NV_DEVICE_V0_DISABLE_DISP,
@@ -352,12 +355,14 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
                /* determine chipset and derive architecture from it */
                if ((boot0 & 0x1f000000) > 0) {
                        device->chipset = (boot0 & 0x1ff00000) >> 20;
+                       device->chiprev = (boot0 & 0x000000ff);
                        switch (device->chipset & 0x1f0) {
                        case 0x010: {
                                if (0x461 & (1 << (device->chipset & 0xf)))
                                        device->card_type = NV_10;
                                else
                                        device->card_type = NV_11;
+                               device->chiprev = 0x00;
                                break;
                        }
                        case 0x020: device->card_type = NV_20; break;
@@ -373,7 +378,8 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
                        case 0x0e0:
                        case 0x0f0:
                        case 0x100: device->card_type = NV_E0; break;
-                       case 0x110: device->card_type = GM100; break;
+                       case 0x110:
+                       case 0x120: device->card_type = GM100; break;
                        default:
                                break;
                        }
@@ -427,6 +433,10 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
                }
 
                nv_debug(device, "crystal freq: %dKHz\n", device->crystal);
+       } else
+       if ( (args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY)) {
+               device->cname = "NULL";
+               device->oclass[NVDEV_SUBDEV_VBIOS] = &nouveau_bios_oclass;
        }
 
        if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_MMIO) &&
index 6295668e29a5897a45e08d2ce09efac9c5aac721..4e74a3376de88d9a695eed859fd17ad136a28c91 100644 (file)
@@ -96,6 +96,49 @@ gm100_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
+#endif
+               break;
+       case 0x124:
+               device->cname = "GM204";
+               device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] =  gm204_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gm107_fuse_oclass;
+#if 0
+               /* looks to be some non-trivial changes */
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
+               /* priv ring says no to 0x10eb14 writes */
+               device->oclass[NVDEV_SUBDEV_THERM  ] = &gm107_therm_oclass;
+#endif
+               device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  gm204_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_TIMER  ] = &gk20a_timer_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  gm107_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_LTC    ] =  gm107_ltc_oclass;
+               device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] =  nv108_pwr_oclass;
+#if 0
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+#endif
+               device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvd0_dmaeng_oclass;
+#if 0
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv108_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_GR     ] =  gm107_graph_oclass;
+#endif
+               device->oclass[NVDEV_ENGINE_DISP   ] =  gm204_disp_oclass;
+#if 0
+               device->oclass[NVDEV_ENGINE_COPY0  ] = &gm204_copy0_oclass;
+               device->oclass[NVDEV_ENGINE_COPY1  ] = &gm204_copy1_oclass;
+               device->oclass[NVDEV_ENGINE_COPY2  ] = &gm204_copy2_oclass;
+               device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
+               device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
+               device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
 #endif
                break;
        default:
index b1b2e484ecfabb1a51426a9737fa3d05a014c30c..674da1f095b29a1c1ecc524fef40eb3b60bc3a35 100644 (file)
@@ -179,6 +179,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_GR     ] =  gk20a_graph_oclass;
                device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &gk20a_volt_oclass;
                break;
        case 0xf0:
                device->cname = "GK110";
index 39890221b91cbba988a6ab33534b757fce2d8718..16db08dfba6ef38645e813481e6d4201d94b695e 100644 (file)
@@ -28,7 +28,7 @@
 #include <subdev/bios/init.h>
 #include <subdev/i2c.h>
 
-#include <engine/disp.h>
+#include "nv50.h"
 
 #include <nvif/class.h>
 
@@ -326,7 +326,7 @@ void
 nouveau_dp_train(struct work_struct *w)
 {
        struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work);
-       struct nouveau_disp *disp = nouveau_disp(outp);
+       struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
        const struct dp_rates *cfg = nouveau_dp_rates;
        struct dp_state _dp = {
                .outp = outp,
@@ -334,8 +334,11 @@ nouveau_dp_train(struct work_struct *w)
        u32 datarate = 0;
        int ret;
 
+       if (!outp->base.info.location && priv->sor.magic)
+               priv->sor.magic(&outp->base);
+
        /* bring capabilities within encoder limits */
-       if (nv_mclass(disp) < GF110_DISP)
+       if (nv_mclass(priv) < GF110_DISP)
                outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED;
        if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) {
                outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT;
index b3df3fe2dc094b6dbebdc861c94450ef48ddf3e2..e2ad0543fb31e252d5662da41da258c4845b543e 100644 (file)
@@ -35,8 +35,8 @@
 
 static struct nouveau_oclass
 gm107_disp_sclass[] = {
-       { GM107_DISP_CORE_CHANNEL_DMA, &nvd0_disp_mast_ofuncs.base },
-       { GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_sync_ofuncs.base },
+       { GM107_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
+       { GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
        { GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
        { GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
        { GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
@@ -44,8 +44,8 @@ gm107_disp_sclass[] = {
 };
 
 static struct nouveau_oclass
-gm107_disp_base_oclass[] = {
-       { GM107_DISP, &nvd0_disp_base_ofuncs },
+gm107_disp_main_oclass[] = {
+       { GM107_DISP, &nvd0_disp_main_ofuncs },
        {}
 };
 
@@ -72,7 +72,7 @@ gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       nv_engine(priv)->sclass = gm107_disp_base_oclass;
+       nv_engine(priv)->sclass = gm107_disp_main_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nvd0_disp_intr;
        INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
@@ -99,9 +99,9 @@ gm107_disp_oclass = &(struct nv50_disp_impl) {
        },
        .base.vblank = &nvd0_disp_vblank_func,
        .base.outp =  nvd0_disp_outp_sclass,
-       .mthd.core = &nve0_disp_mast_mthd_chan,
-       .mthd.base = &nvd0_disp_sync_mthd_chan,
+       .mthd.core = &nve0_disp_core_mthd_chan,
+       .mthd.base = &nvd0_disp_base_mthd_chan,
        .mthd.ovly = &nve0_disp_ovly_mthd_chan,
        .mthd.prev = -0x020000,
-       .head.scanoutpos = nvd0_disp_base_scanoutpos,
+       .head.scanoutpos = nvd0_disp_main_scanoutpos,
 }.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/gm204.c b/drivers/gpu/drm/nouveau/core/engine/disp/gm204.c
new file mode 100644 (file)
index 0000000..672ded7
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <engine/software.h>
+#include <engine/disp.h>
+
+#include <nvif/class.h>
+
+#include "nv50.h"
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nouveau_oclass
+gm204_disp_sclass[] = {
+       { GM204_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
+       { GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
+       { GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
+       { GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
+       { GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
+       {}
+};
+
+static struct nouveau_oclass
+gm204_disp_main_oclass[] = {
+       { GM204_DISP, &nvd0_disp_main_ofuncs },
+       {}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+gm204_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+              struct nouveau_oclass *oclass, void *data, u32 size,
+              struct nouveau_object **pobject)
+{
+       struct nv50_disp_priv *priv;
+       int heads = nv_rd32(parent, 0x022448);
+       int ret;
+
+       ret = nouveau_disp_create(parent, engine, oclass, heads,
+                                 "PDISP", "display", &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
+       if (ret)
+               return ret;
+
+       nv_engine(priv)->sclass = gm204_disp_main_oclass;
+       nv_engine(priv)->cclass = &nv50_disp_cclass;
+       nv_subdev(priv)->intr = nvd0_disp_intr;
+       INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
+       priv->sclass = gm204_disp_sclass;
+       priv->head.nr = heads;
+       priv->dac.nr = 3;
+       priv->sor.nr = 4;
+       priv->dac.power = nv50_dac_power;
+       priv->dac.sense = nv50_dac_sense;
+       priv->sor.power = nv50_sor_power;
+       priv->sor.hda_eld = nvd0_hda_eld;
+       priv->sor.hdmi = nvd0_hdmi_ctrl;
+       priv->sor.magic = gm204_sor_magic;
+       return 0;
+}
+
+struct nouveau_oclass *
+gm204_disp_outp_sclass[] = {
+       &gm204_sor_dp_impl.base.base,
+       NULL
+};
+
+struct nouveau_oclass *
+gm204_disp_oclass = &(struct nv50_disp_impl) {
+       .base.base.handle = NV_ENGINE(DISP, 0x07),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = gm204_disp_ctor,
+               .dtor = _nouveau_disp_dtor,
+               .init = _nouveau_disp_init,
+               .fini = _nouveau_disp_fini,
+       },
+       .base.vblank = &nvd0_disp_vblank_func,
+       .base.outp =  gm204_disp_outp_sclass,
+       .mthd.core = &nve0_disp_core_mthd_chan,
+       .mthd.base = &nvd0_disp_base_mthd_chan,
+       .mthd.ovly = &nve0_disp_ovly_mthd_chan,
+       .mthd.prev = -0x020000,
+       .head.scanoutpos = nvd0_disp_main_scanoutpos,
+}.base.base;
index 2df3a937037de7c55d94f345bcdd8f2eeb88576e..44a8290aaea5cf2a0e7358cfa48cb9e7ad11dc27 100644 (file)
@@ -88,12 +88,14 @@ nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
 {
        struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
        nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000000 << index);
+       nv_wr32(priv, 0x610020, 0x00000001 << index);
 }
 
 static void
 nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
 {
        struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
+       nv_wr32(priv, 0x610020, 0x00000001 << index);
        nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000001 << index);
 }
 
@@ -374,7 +376,7 @@ nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head,
 }
 
 const struct nv50_disp_mthd_list
-nv50_disp_mast_mthd_base = {
+nv50_disp_core_mthd_base = {
        .mthd = 0x0000,
        .addr = 0x000000,
        .data = {
@@ -387,7 +389,7 @@ nv50_disp_mast_mthd_base = {
 };
 
 static const struct nv50_disp_mthd_list
-nv50_disp_mast_mthd_dac = {
+nv50_disp_core_mthd_dac = {
        .mthd = 0x0080,
        .addr = 0x000008,
        .data = {
@@ -399,7 +401,7 @@ nv50_disp_mast_mthd_dac = {
 };
 
 const struct nv50_disp_mthd_list
-nv50_disp_mast_mthd_sor = {
+nv50_disp_core_mthd_sor = {
        .mthd = 0x0040,
        .addr = 0x000008,
        .data = {
@@ -409,7 +411,7 @@ nv50_disp_mast_mthd_sor = {
 };
 
 const struct nv50_disp_mthd_list
-nv50_disp_mast_mthd_pior = {
+nv50_disp_core_mthd_pior = {
        .mthd = 0x0040,
        .addr = 0x000008,
        .data = {
@@ -419,7 +421,7 @@ nv50_disp_mast_mthd_pior = {
 };
 
 static const struct nv50_disp_mthd_list
-nv50_disp_mast_mthd_head = {
+nv50_disp_core_mthd_head = {
        .mthd = 0x0400,
        .addr = 0x000540,
        .data = {
@@ -466,21 +468,21 @@ nv50_disp_mast_mthd_head = {
 };
 
 static const struct nv50_disp_mthd_chan
-nv50_disp_mast_mthd_chan = {
+nv50_disp_core_mthd_chan = {
        .name = "Core",
        .addr = 0x000000,
        .data = {
-               { "Global", 1, &nv50_disp_mast_mthd_base },
-               {    "DAC", 3, &nv50_disp_mast_mthd_dac  },
-               {    "SOR", 2, &nv50_disp_mast_mthd_sor  },
-               {   "PIOR", 3, &nv50_disp_mast_mthd_pior },
-               {   "HEAD", 2, &nv50_disp_mast_mthd_head },
+               { "Global", 1, &nv50_disp_core_mthd_base },
+               {    "DAC", 3, &nv50_disp_core_mthd_dac  },
+               {    "SOR", 2, &nv50_disp_core_mthd_sor  },
+               {   "PIOR", 3, &nv50_disp_core_mthd_pior },
+               {   "HEAD", 2, &nv50_disp_core_mthd_head },
                {}
        }
 };
 
 int
-nv50_disp_mast_ctor(struct nouveau_object *parent,
+nv50_disp_core_ctor(struct nouveau_object *parent,
                    struct nouveau_object *engine,
                    struct nouveau_oclass *oclass, void *data, u32 size,
                    struct nouveau_object **pobject)
@@ -509,7 +511,7 @@ nv50_disp_mast_ctor(struct nouveau_object *parent,
 }
 
 static int
-nv50_disp_mast_init(struct nouveau_object *object)
+nv50_disp_core_init(struct nouveau_object *object)
 {
        struct nv50_disp_priv *priv = (void *)object->engine;
        struct nv50_disp_dmac *mast = (void *)object;
@@ -546,7 +548,7 @@ nv50_disp_mast_init(struct nouveau_object *object)
 }
 
 static int
-nv50_disp_mast_fini(struct nouveau_object *object, bool suspend)
+nv50_disp_core_fini(struct nouveau_object *object, bool suspend)
 {
        struct nv50_disp_priv *priv = (void *)object->engine;
        struct nv50_disp_dmac *mast = (void *)object;
@@ -567,11 +569,11 @@ nv50_disp_mast_fini(struct nouveau_object *object, bool suspend)
 }
 
 struct nv50_disp_chan_impl
-nv50_disp_mast_ofuncs = {
-       .base.ctor = nv50_disp_mast_ctor,
+nv50_disp_core_ofuncs = {
+       .base.ctor = nv50_disp_core_ctor,
        .base.dtor = nv50_disp_dmac_dtor,
-       .base.init = nv50_disp_mast_init,
-       .base.fini = nv50_disp_mast_fini,
+       .base.init = nv50_disp_core_init,
+       .base.fini = nv50_disp_core_fini,
        .base.map  = nv50_disp_chan_map,
        .base.ntfy = nv50_disp_chan_ntfy,
        .base.rd32 = nv50_disp_chan_rd32,
@@ -586,7 +588,7 @@ nv50_disp_mast_ofuncs = {
  ******************************************************************************/
 
 static const struct nv50_disp_mthd_list
-nv50_disp_sync_mthd_base = {
+nv50_disp_base_mthd_base = {
        .mthd = 0x0000,
        .addr = 0x000000,
        .data = {
@@ -611,7 +613,7 @@ nv50_disp_sync_mthd_base = {
 };
 
 const struct nv50_disp_mthd_list
-nv50_disp_sync_mthd_image = {
+nv50_disp_base_mthd_image = {
        .mthd = 0x0400,
        .addr = 0x000000,
        .data = {
@@ -625,18 +627,18 @@ nv50_disp_sync_mthd_image = {
 };
 
 static const struct nv50_disp_mthd_chan
-nv50_disp_sync_mthd_chan = {
+nv50_disp_base_mthd_chan = {
        .name = "Base",
        .addr = 0x000540,
        .data = {
-               { "Global", 1, &nv50_disp_sync_mthd_base },
-               {  "Image", 2, &nv50_disp_sync_mthd_image },
+               { "Global", 1, &nv50_disp_base_mthd_base },
+               {  "Image", 2, &nv50_disp_base_mthd_image },
                {}
        }
 };
 
 int
-nv50_disp_sync_ctor(struct nouveau_object *parent,
+nv50_disp_base_ctor(struct nouveau_object *parent,
                    struct nouveau_object *engine,
                    struct nouveau_oclass *oclass, void *data, u32 size,
                    struct nouveau_object **pobject)
@@ -669,8 +671,8 @@ nv50_disp_sync_ctor(struct nouveau_object *parent,
 }
 
 struct nv50_disp_chan_impl
-nv50_disp_sync_ofuncs = {
-       .base.ctor = nv50_disp_sync_ctor,
+nv50_disp_base_ofuncs = {
+       .base.ctor = nv50_disp_base_ctor,
        .base.dtor = nv50_disp_dmac_dtor,
        .base.init = nv50_disp_dmac_init,
        .base.fini = nv50_disp_dmac_fini,
@@ -942,7 +944,7 @@ nv50_disp_curs_ofuncs = {
  ******************************************************************************/
 
 int
-nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0)
+nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0)
 {
        const u32 blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
        const u32 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
@@ -974,7 +976,7 @@ nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0)
 }
 
 int
-nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd,
+nv50_disp_main_mthd(struct nouveau_object *object, u32 mthd,
                    void *data, u32 size)
 {
        const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine);
@@ -1098,7 +1100,7 @@ nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd,
 }
 
 int
-nv50_disp_base_ctor(struct nouveau_object *parent,
+nv50_disp_main_ctor(struct nouveau_object *parent,
                    struct nouveau_object *engine,
                    struct nouveau_oclass *oclass, void *data, u32 size,
                    struct nouveau_object **pobject)
@@ -1118,7 +1120,7 @@ nv50_disp_base_ctor(struct nouveau_object *parent,
 }
 
 void
-nv50_disp_base_dtor(struct nouveau_object *object)
+nv50_disp_main_dtor(struct nouveau_object *object)
 {
        struct nv50_disp_base *base = (void *)object;
        nouveau_ramht_ref(NULL, &base->ramht);
@@ -1126,7 +1128,7 @@ nv50_disp_base_dtor(struct nouveau_object *object)
 }
 
 static int
-nv50_disp_base_init(struct nouveau_object *object)
+nv50_disp_main_init(struct nouveau_object *object)
 {
        struct nv50_disp_priv *priv = (void *)object->engine;
        struct nv50_disp_base *base = (void *)object;
@@ -1194,7 +1196,7 @@ nv50_disp_base_init(struct nouveau_object *object)
 }
 
 static int
-nv50_disp_base_fini(struct nouveau_object *object, bool suspend)
+nv50_disp_main_fini(struct nouveau_object *object, bool suspend)
 {
        struct nv50_disp_priv *priv = (void *)object->engine;
        struct nv50_disp_base *base = (void *)object;
@@ -1207,25 +1209,25 @@ nv50_disp_base_fini(struct nouveau_object *object, bool suspend)
 }
 
 struct nouveau_ofuncs
-nv50_disp_base_ofuncs = {
-       .ctor = nv50_disp_base_ctor,
-       .dtor = nv50_disp_base_dtor,
-       .init = nv50_disp_base_init,
-       .fini = nv50_disp_base_fini,
-       .mthd = nv50_disp_base_mthd,
+nv50_disp_main_ofuncs = {
+       .ctor = nv50_disp_main_ctor,
+       .dtor = nv50_disp_main_dtor,
+       .init = nv50_disp_main_init,
+       .fini = nv50_disp_main_fini,
+       .mthd = nv50_disp_main_mthd,
        .ntfy = nouveau_disp_ntfy,
 };
 
 static struct nouveau_oclass
-nv50_disp_base_oclass[] = {
-       { NV50_DISP, &nv50_disp_base_ofuncs },
+nv50_disp_main_oclass[] = {
+       { NV50_DISP, &nv50_disp_main_ofuncs },
        {}
 };
 
 static struct nouveau_oclass
 nv50_disp_sclass[] = {
-       { NV50_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base },
-       { NV50_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base },
+       { NV50_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
+       { NV50_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
        { NV50_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
        { NV50_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
        { NV50_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
@@ -1974,7 +1976,7 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       nv_engine(priv)->sclass = nv50_disp_base_oclass;
+       nv_engine(priv)->sclass = nv50_disp_main_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nv50_disp_intr;
        INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
@@ -2007,9 +2009,9 @@ nv50_disp_oclass = &(struct nv50_disp_impl) {
        },
        .base.vblank = &nv50_disp_vblank_func,
        .base.outp =  nv50_disp_outp_sclass,
-       .mthd.core = &nv50_disp_mast_mthd_chan,
-       .mthd.base = &nv50_disp_sync_mthd_chan,
+       .mthd.core = &nv50_disp_core_mthd_chan,
+       .mthd.base = &nv50_disp_base_mthd_chan,
        .mthd.ovly = &nv50_disp_ovly_mthd_chan,
        .mthd.prev = 0x000004,
-       .head.scanoutpos = nv50_disp_base_scanoutpos,
+       .head.scanoutpos = nv50_disp_main_scanoutpos,
 }.base.base;
index 5279feefec062210706e087b315e802a84648913..7f08078ee9253fc41b73fe0a8b682359dca1edc4 100644 (file)
@@ -42,6 +42,7 @@ struct nv50_disp_priv {
                int (*hda_eld)(NV50_DISP_MTHD_V1);
                int (*hdmi)(NV50_DISP_MTHD_V1);
                u32 lvdsconf;
+               void (*magic)(struct nvkm_output *);
        } sor;
        struct {
                int nr;
@@ -63,10 +64,10 @@ struct nv50_disp_impl {
        } head;
 };
 
-int nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0);
-int nv50_disp_base_mthd(struct nouveau_object *, u32, void *, u32);
+int nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0);
+int nv50_disp_main_mthd(struct nouveau_object *, u32, void *, u32);
 
-int nvd0_disp_base_scanoutpos(NV50_DISP_MTHD_V0);
+int nvd0_disp_main_scanoutpos(NV50_DISP_MTHD_V0);
 
 int nv50_dac_power(NV50_DISP_MTHD_V1);
 int nv50_dac_sense(NV50_DISP_MTHD_V1);
@@ -169,18 +170,18 @@ struct nv50_disp_mthd_chan {
        } data[];
 };
 
-extern struct nv50_disp_chan_impl nv50_disp_mast_ofuncs;
-int nv50_disp_mast_ctor(struct nouveau_object *, struct nouveau_object *,
+extern struct nv50_disp_chan_impl nv50_disp_core_ofuncs;
+int nv50_disp_core_ctor(struct nouveau_object *, struct nouveau_object *,
                        struct nouveau_oclass *, void *, u32,
                        struct nouveau_object **);
-extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_base;
-extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_sor;
-extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_pior;
-extern struct nv50_disp_chan_impl nv50_disp_sync_ofuncs;
-int nv50_disp_sync_ctor(struct nouveau_object *, struct nouveau_object *,
+extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_base;
+extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_sor;
+extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_pior;
+extern struct nv50_disp_chan_impl nv50_disp_base_ofuncs;
+int nv50_disp_base_ctor(struct nouveau_object *, struct nouveau_object *,
                        struct nouveau_oclass *, void *, u32,
                        struct nouveau_object **);
-extern const struct nv50_disp_mthd_list nv50_disp_sync_mthd_image;
+extern const struct nv50_disp_mthd_list nv50_disp_base_mthd_image;
 extern struct nv50_disp_chan_impl nv50_disp_ovly_ofuncs;
 int nv50_disp_ovly_ctor(struct nouveau_object *, struct nouveau_object *,
                        struct nouveau_oclass *, void *, u32,
@@ -194,12 +195,12 @@ extern struct nv50_disp_chan_impl nv50_disp_curs_ofuncs;
 int nv50_disp_curs_ctor(struct nouveau_object *, struct nouveau_object *,
                        struct nouveau_oclass *, void *, u32,
                        struct nouveau_object **);
-extern struct nouveau_ofuncs nv50_disp_base_ofuncs;
-int  nv50_disp_base_ctor(struct nouveau_object *, struct nouveau_object *,
+extern struct nouveau_ofuncs nv50_disp_main_ofuncs;
+int  nv50_disp_main_ctor(struct nouveau_object *, struct nouveau_object *,
                         struct nouveau_oclass *, void *, u32,
                         struct nouveau_object **);
-void nv50_disp_base_dtor(struct nouveau_object *);
-extern struct nouveau_omthds nv50_disp_base_omthds[];
+void nv50_disp_main_dtor(struct nouveau_object *);
+extern struct nouveau_omthds nv50_disp_main_omthds[];
 extern struct nouveau_oclass nv50_disp_cclass;
 void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head,
                         const struct nv50_disp_mthd_chan *);
@@ -207,31 +208,31 @@ void nv50_disp_intr_supervisor(struct work_struct *);
 void nv50_disp_intr(struct nouveau_subdev *);
 extern const struct nvkm_event_func nv50_disp_vblank_func;
 
-extern const struct nv50_disp_mthd_chan nv84_disp_mast_mthd_chan;
-extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_dac;
-extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_head;
-extern const struct nv50_disp_mthd_chan nv84_disp_sync_mthd_chan;
+extern const struct nv50_disp_mthd_chan nv84_disp_core_mthd_chan;
+extern const struct nv50_disp_mthd_list nv84_disp_core_mthd_dac;
+extern const struct nv50_disp_mthd_list nv84_disp_core_mthd_head;
+extern const struct nv50_disp_mthd_chan nv84_disp_base_mthd_chan;
 extern const struct nv50_disp_mthd_chan nv84_disp_ovly_mthd_chan;
 
-extern const struct nv50_disp_mthd_chan nv94_disp_mast_mthd_chan;
+extern const struct nv50_disp_mthd_chan nv94_disp_core_mthd_chan;
 
-extern struct nv50_disp_chan_impl nvd0_disp_mast_ofuncs;
-extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_base;
-extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_dac;
-extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_sor;
-extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_pior;
-extern struct nv50_disp_chan_impl nvd0_disp_sync_ofuncs;
+extern struct nv50_disp_chan_impl nvd0_disp_core_ofuncs;
+extern const struct nv50_disp_mthd_list nvd0_disp_core_mthd_base;
+extern const struct nv50_disp_mthd_list nvd0_disp_core_mthd_dac;
+extern const struct nv50_disp_mthd_list nvd0_disp_core_mthd_sor;
+extern const struct nv50_disp_mthd_list nvd0_disp_core_mthd_pior;
+extern struct nv50_disp_chan_impl nvd0_disp_base_ofuncs;
 extern struct nv50_disp_chan_impl nvd0_disp_ovly_ofuncs;
-extern const struct nv50_disp_mthd_chan nvd0_disp_sync_mthd_chan;
+extern const struct nv50_disp_mthd_chan nvd0_disp_base_mthd_chan;
 extern struct nv50_disp_chan_impl nvd0_disp_oimm_ofuncs;
 extern struct nv50_disp_chan_impl nvd0_disp_curs_ofuncs;
-extern struct nouveau_ofuncs nvd0_disp_base_ofuncs;
+extern struct nouveau_ofuncs nvd0_disp_main_ofuncs;
 extern struct nouveau_oclass nvd0_disp_cclass;
 void nvd0_disp_intr_supervisor(struct work_struct *);
 void nvd0_disp_intr(struct nouveau_subdev *);
 extern const struct nvkm_event_func nvd0_disp_vblank_func;
 
-extern const struct nv50_disp_mthd_chan nve0_disp_mast_mthd_chan;
+extern const struct nv50_disp_mthd_chan nve0_disp_core_mthd_chan;
 extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan;
 
 extern struct nvkm_output_dp_impl nv50_pior_dp_impl;
@@ -242,6 +243,10 @@ int nv94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int);
 extern struct nouveau_oclass *nv94_disp_outp_sclass[];
 
 extern struct nvkm_output_dp_impl nvd0_sor_dp_impl;
+int nvd0_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool);
 extern struct nouveau_oclass *nvd0_disp_outp_sclass[];
 
+void gm204_sor_magic(struct nvkm_output *outp);
+extern struct nvkm_output_dp_impl gm204_sor_dp_impl;
+
 #endif
index d36284715b2ab0f20ae26bce925fe05b3b1bea67..13eff5e4ee515e638070374ca1615acb095b7120 100644 (file)
@@ -34,7 +34,7 @@
  ******************************************************************************/
 
 const struct nv50_disp_mthd_list
-nv84_disp_mast_mthd_dac = {
+nv84_disp_core_mthd_dac = {
        .mthd = 0x0080,
        .addr = 0x000008,
        .data = {
@@ -46,7 +46,7 @@ nv84_disp_mast_mthd_dac = {
 };
 
 const struct nv50_disp_mthd_list
-nv84_disp_mast_mthd_head = {
+nv84_disp_core_mthd_head = {
        .mthd = 0x0400,
        .addr = 0x000540,
        .data = {
@@ -98,15 +98,15 @@ nv84_disp_mast_mthd_head = {
 };
 
 const struct nv50_disp_mthd_chan
-nv84_disp_mast_mthd_chan = {
+nv84_disp_core_mthd_chan = {
        .name = "Core",
        .addr = 0x000000,
        .data = {
-               { "Global", 1, &nv50_disp_mast_mthd_base },
-               {    "DAC", 3, &nv84_disp_mast_mthd_dac  },
-               {    "SOR", 2, &nv50_disp_mast_mthd_sor  },
-               {   "PIOR", 3, &nv50_disp_mast_mthd_pior },
-               {   "HEAD", 2, &nv84_disp_mast_mthd_head },
+               { "Global", 1, &nv50_disp_core_mthd_base },
+               {    "DAC", 3, &nv84_disp_core_mthd_dac  },
+               {    "SOR", 2, &nv50_disp_core_mthd_sor  },
+               {   "PIOR", 3, &nv50_disp_core_mthd_pior },
+               {   "HEAD", 2, &nv84_disp_core_mthd_head },
                {}
        }
 };
@@ -116,7 +116,7 @@ nv84_disp_mast_mthd_chan = {
  ******************************************************************************/
 
 static const struct nv50_disp_mthd_list
-nv84_disp_sync_mthd_base = {
+nv84_disp_base_mthd_base = {
        .mthd = 0x0000,
        .addr = 0x000000,
        .data = {
@@ -146,12 +146,12 @@ nv84_disp_sync_mthd_base = {
 };
 
 const struct nv50_disp_mthd_chan
-nv84_disp_sync_mthd_chan = {
+nv84_disp_base_mthd_chan = {
        .name = "Base",
        .addr = 0x000540,
        .data = {
-               { "Global", 1, &nv84_disp_sync_mthd_base },
-               {  "Image", 2, &nv50_disp_sync_mthd_image },
+               { "Global", 1, &nv84_disp_base_mthd_base },
+               {  "Image", 2, &nv50_disp_base_mthd_image },
                {}
        }
 };
@@ -204,8 +204,8 @@ nv84_disp_ovly_mthd_chan = {
 
 static struct nouveau_oclass
 nv84_disp_sclass[] = {
-       { G82_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base },
-       { G82_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base },
+       { G82_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
+       { G82_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
        { G82_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
        { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
        { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
@@ -213,8 +213,8 @@ nv84_disp_sclass[] = {
 };
 
 static struct nouveau_oclass
-nv84_disp_base_oclass[] = {
-       { G82_DISP, &nv50_disp_base_ofuncs },
+nv84_disp_main_oclass[] = {
+       { G82_DISP, &nv50_disp_main_ofuncs },
        {}
 };
 
@@ -240,7 +240,7 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       nv_engine(priv)->sclass = nv84_disp_base_oclass;
+       nv_engine(priv)->sclass = nv84_disp_main_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nv50_disp_intr;
        INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
@@ -268,9 +268,9 @@ nv84_disp_oclass = &(struct nv50_disp_impl) {
        },
        .base.vblank = &nv50_disp_vblank_func,
        .base.outp =  nv50_disp_outp_sclass,
-       .mthd.core = &nv84_disp_mast_mthd_chan,
-       .mthd.base = &nv84_disp_sync_mthd_chan,
+       .mthd.core = &nv84_disp_core_mthd_chan,
+       .mthd.base = &nv84_disp_base_mthd_chan,
        .mthd.ovly = &nv84_disp_ovly_mthd_chan,
        .mthd.prev = 0x000004,
-       .head.scanoutpos = nv50_disp_base_scanoutpos,
+       .head.scanoutpos = nv50_disp_main_scanoutpos,
 }.base.base;
index a117064002b1413a499a5a644ebd0c439abcdf75..2bb7ac5cd0e65d22fbce59dbfd9e1a915790cd26 100644 (file)
@@ -34,7 +34,7 @@
  ******************************************************************************/
 
 const struct nv50_disp_mthd_list
-nv94_disp_mast_mthd_sor = {
+nv94_disp_core_mthd_sor = {
        .mthd = 0x0040,
        .addr = 0x000008,
        .data = {
@@ -44,15 +44,15 @@ nv94_disp_mast_mthd_sor = {
 };
 
 const struct nv50_disp_mthd_chan
-nv94_disp_mast_mthd_chan = {
+nv94_disp_core_mthd_chan = {
        .name = "Core",
        .addr = 0x000000,
        .data = {
-               { "Global", 1, &nv50_disp_mast_mthd_base },
-               {    "DAC", 3, &nv84_disp_mast_mthd_dac  },
-               {    "SOR", 4, &nv94_disp_mast_mthd_sor  },
-               {   "PIOR", 3, &nv50_disp_mast_mthd_pior },
-               {   "HEAD", 2, &nv84_disp_mast_mthd_head },
+               { "Global", 1, &nv50_disp_core_mthd_base },
+               {    "DAC", 3, &nv84_disp_core_mthd_dac  },
+               {    "SOR", 4, &nv94_disp_core_mthd_sor  },
+               {   "PIOR", 3, &nv50_disp_core_mthd_pior },
+               {   "HEAD", 2, &nv84_disp_core_mthd_head },
                {}
        }
 };
@@ -63,8 +63,8 @@ nv94_disp_mast_mthd_chan = {
 
 static struct nouveau_oclass
 nv94_disp_sclass[] = {
-       { GT206_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base },
-       { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base },
+       { GT206_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
+       { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
        { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
        { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
        { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
@@ -72,8 +72,8 @@ nv94_disp_sclass[] = {
 };
 
 static struct nouveau_oclass
-nv94_disp_base_oclass[] = {
-       { GT206_DISP, &nv50_disp_base_ofuncs },
+nv94_disp_main_oclass[] = {
+       { GT206_DISP, &nv50_disp_main_ofuncs },
        {}
 };
 
@@ -99,7 +99,7 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       nv_engine(priv)->sclass = nv94_disp_base_oclass;
+       nv_engine(priv)->sclass = nv94_disp_main_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nv50_disp_intr;
        INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
@@ -134,9 +134,9 @@ nv94_disp_oclass = &(struct nv50_disp_impl) {
        },
        .base.vblank = &nv50_disp_vblank_func,
        .base.outp =  nv94_disp_outp_sclass,
-       .mthd.core = &nv94_disp_mast_mthd_chan,
-       .mthd.base = &nv84_disp_sync_mthd_chan,
+       .mthd.core = &nv94_disp_core_mthd_chan,
+       .mthd.base = &nv84_disp_base_mthd_chan,
        .mthd.ovly = &nv84_disp_ovly_mthd_chan,
        .mthd.prev = 0x000004,
-       .head.scanoutpos = nv50_disp_base_scanoutpos,
+       .head.scanoutpos = nv50_disp_main_scanoutpos,
 }.base.base;
index c67e68aadd45987ae1f5dc6fb0a48a73102b1fcc..b32456c9494fcf9432de07ca6de65b5c236bd4a8 100644 (file)
@@ -80,8 +80,8 @@ nva0_disp_ovly_mthd_chan = {
 
 static struct nouveau_oclass
 nva0_disp_sclass[] = {
-       { GT200_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base },
-       { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base },
+       { GT200_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
+       { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
        { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
        { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
        { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
@@ -89,8 +89,8 @@ nva0_disp_sclass[] = {
 };
 
 static struct nouveau_oclass
-nva0_disp_base_oclass[] = {
-       { GT200_DISP, &nv50_disp_base_ofuncs },
+nva0_disp_main_oclass[] = {
+       { GT200_DISP, &nv50_disp_main_ofuncs },
        {}
 };
 
@@ -116,7 +116,7 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       nv_engine(priv)->sclass = nva0_disp_base_oclass;
+       nv_engine(priv)->sclass = nva0_disp_main_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nv50_disp_intr;
        INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
@@ -144,9 +144,9 @@ nva0_disp_oclass = &(struct nv50_disp_impl) {
        },
        .base.vblank = &nv50_disp_vblank_func,
        .base.outp =  nv50_disp_outp_sclass,
-       .mthd.core = &nv84_disp_mast_mthd_chan,
-       .mthd.base = &nv84_disp_sync_mthd_chan,
+       .mthd.core = &nv84_disp_core_mthd_chan,
+       .mthd.base = &nv84_disp_base_mthd_chan,
        .mthd.ovly = &nva0_disp_ovly_mthd_chan,
        .mthd.prev = 0x000004,
-       .head.scanoutpos = nv50_disp_base_scanoutpos,
+       .head.scanoutpos = nv50_disp_main_scanoutpos,
 }.base.base;
index 22969f355aae66da0102bf722a87cbff81b529fc..951d79f9b781974bedfa39376464ced4731ef27c 100644 (file)
@@ -35,8 +35,8 @@
 
 static struct nouveau_oclass
 nva3_disp_sclass[] = {
-       { GT214_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base },
-       { GT214_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base },
+       { GT214_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
+       { GT214_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
        { GT214_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
        { GT214_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
        { GT214_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
@@ -44,8 +44,8 @@ nva3_disp_sclass[] = {
 };
 
 static struct nouveau_oclass
-nva3_disp_base_oclass[] = {
-       { GT214_DISP, &nv50_disp_base_ofuncs },
+nva3_disp_main_oclass[] = {
+       { GT214_DISP, &nv50_disp_main_ofuncs },
        {}
 };
 
@@ -71,7 +71,7 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       nv_engine(priv)->sclass = nva3_disp_base_oclass;
+       nv_engine(priv)->sclass = nva3_disp_main_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nv50_disp_intr;
        INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
@@ -100,9 +100,9 @@ nva3_disp_oclass = &(struct nv50_disp_impl) {
        },
        .base.vblank = &nv50_disp_vblank_func,
        .base.outp =  nv94_disp_outp_sclass,
-       .mthd.core = &nv94_disp_mast_mthd_chan,
-       .mthd.base = &nv84_disp_sync_mthd_chan,
+       .mthd.core = &nv94_disp_core_mthd_chan,
+       .mthd.base = &nv84_disp_base_mthd_chan,
        .mthd.ovly = &nv84_disp_ovly_mthd_chan,
        .mthd.prev = 0x000004,
-       .head.scanoutpos = nv50_disp_base_scanoutpos,
+       .head.scanoutpos = nv50_disp_main_scanoutpos,
 }.base.base;
index 747e64bb9c06c935e1318a57ac7d8b879b473366..181a2d57e356c8570ec854ac5bd7b87d6cf506e4 100644 (file)
@@ -51,12 +51,14 @@ nvd0_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
 {
        struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
        nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000000 << index);
+       nv_wr32(priv, 0x61008c, 0x00000001 << index);
 }
 
 static void
 nvd0_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
 {
        struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
+       nv_wr32(priv, 0x61008c, 0x00000001 << index);
        nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000001 << index);
 }
 
@@ -151,7 +153,7 @@ nvd0_disp_dmac_fini(struct nouveau_object *object, bool suspend)
  ******************************************************************************/
 
 const struct nv50_disp_mthd_list
-nvd0_disp_mast_mthd_base = {
+nvd0_disp_core_mthd_base = {
        .mthd = 0x0000,
        .addr = 0x000000,
        .data = {
@@ -164,7 +166,7 @@ nvd0_disp_mast_mthd_base = {
 };
 
 const struct nv50_disp_mthd_list
-nvd0_disp_mast_mthd_dac = {
+nvd0_disp_core_mthd_dac = {
        .mthd = 0x0020,
        .addr = 0x000020,
        .data = {
@@ -177,7 +179,7 @@ nvd0_disp_mast_mthd_dac = {
 };
 
 const struct nv50_disp_mthd_list
-nvd0_disp_mast_mthd_sor = {
+nvd0_disp_core_mthd_sor = {
        .mthd = 0x0020,
        .addr = 0x000020,
        .data = {
@@ -190,7 +192,7 @@ nvd0_disp_mast_mthd_sor = {
 };
 
 const struct nv50_disp_mthd_list
-nvd0_disp_mast_mthd_pior = {
+nvd0_disp_core_mthd_pior = {
        .mthd = 0x0020,
        .addr = 0x000020,
        .data = {
@@ -203,7 +205,7 @@ nvd0_disp_mast_mthd_pior = {
 };
 
 static const struct nv50_disp_mthd_list
-nvd0_disp_mast_mthd_head = {
+nvd0_disp_core_mthd_head = {
        .mthd = 0x0300,
        .addr = 0x000300,
        .data = {
@@ -277,21 +279,21 @@ nvd0_disp_mast_mthd_head = {
 };
 
 static const struct nv50_disp_mthd_chan
-nvd0_disp_mast_mthd_chan = {
+nvd0_disp_core_mthd_chan = {
        .name = "Core",
        .addr = 0x000000,
        .data = {
-               { "Global", 1, &nvd0_disp_mast_mthd_base },
-               {    "DAC", 3, &nvd0_disp_mast_mthd_dac  },
-               {    "SOR", 8, &nvd0_disp_mast_mthd_sor  },
-               {   "PIOR", 4, &nvd0_disp_mast_mthd_pior },
-               {   "HEAD", 4, &nvd0_disp_mast_mthd_head },
+               { "Global", 1, &nvd0_disp_core_mthd_base },
+               {    "DAC", 3, &nvd0_disp_core_mthd_dac  },
+               {    "SOR", 8, &nvd0_disp_core_mthd_sor  },
+               {   "PIOR", 4, &nvd0_disp_core_mthd_pior },
+               {   "HEAD", 4, &nvd0_disp_core_mthd_head },
                {}
        }
 };
 
 static int
-nvd0_disp_mast_init(struct nouveau_object *object)
+nvd0_disp_core_init(struct nouveau_object *object)
 {
        struct nv50_disp_priv *priv = (void *)object->engine;
        struct nv50_disp_dmac *mast = (void *)object;
@@ -322,7 +324,7 @@ nvd0_disp_mast_init(struct nouveau_object *object)
 }
 
 static int
-nvd0_disp_mast_fini(struct nouveau_object *object, bool suspend)
+nvd0_disp_core_fini(struct nouveau_object *object, bool suspend)
 {
        struct nv50_disp_priv *priv = (void *)object->engine;
        struct nv50_disp_dmac *mast = (void *)object;
@@ -344,11 +346,11 @@ nvd0_disp_mast_fini(struct nouveau_object *object, bool suspend)
 }
 
 struct nv50_disp_chan_impl
-nvd0_disp_mast_ofuncs = {
-       .base.ctor = nv50_disp_mast_ctor,
+nvd0_disp_core_ofuncs = {
+       .base.ctor = nv50_disp_core_ctor,
        .base.dtor = nv50_disp_dmac_dtor,
-       .base.init = nvd0_disp_mast_init,
-       .base.fini = nvd0_disp_mast_fini,
+       .base.init = nvd0_disp_core_init,
+       .base.fini = nvd0_disp_core_fini,
        .base.ntfy = nv50_disp_chan_ntfy,
        .base.map  = nv50_disp_chan_map,
        .base.rd32 = nv50_disp_chan_rd32,
@@ -363,7 +365,7 @@ nvd0_disp_mast_ofuncs = {
  ******************************************************************************/
 
 static const struct nv50_disp_mthd_list
-nvd0_disp_sync_mthd_base = {
+nvd0_disp_base_mthd_base = {
        .mthd = 0x0000,
        .addr = 0x000000,
        .data = {
@@ -413,7 +415,7 @@ nvd0_disp_sync_mthd_base = {
 };
 
 static const struct nv50_disp_mthd_list
-nvd0_disp_sync_mthd_image = {
+nvd0_disp_base_mthd_image = {
        .mthd = 0x0400,
        .addr = 0x000400,
        .data = {
@@ -427,19 +429,19 @@ nvd0_disp_sync_mthd_image = {
 };
 
 const struct nv50_disp_mthd_chan
-nvd0_disp_sync_mthd_chan = {
+nvd0_disp_base_mthd_chan = {
        .name = "Base",
        .addr = 0x001000,
        .data = {
-               { "Global", 1, &nvd0_disp_sync_mthd_base },
-               {  "Image", 2, &nvd0_disp_sync_mthd_image },
+               { "Global", 1, &nvd0_disp_base_mthd_base },
+               {  "Image", 2, &nvd0_disp_base_mthd_image },
                {}
        }
 };
 
 struct nv50_disp_chan_impl
-nvd0_disp_sync_ofuncs = {
-       .base.ctor = nv50_disp_sync_ctor,
+nvd0_disp_base_ofuncs = {
+       .base.ctor = nv50_disp_base_ctor,
        .base.dtor = nv50_disp_dmac_dtor,
        .base.init = nvd0_disp_dmac_init,
        .base.fini = nvd0_disp_dmac_fini,
@@ -624,7 +626,7 @@ nvd0_disp_curs_ofuncs = {
  ******************************************************************************/
 
 int
-nvd0_disp_base_scanoutpos(NV50_DISP_MTHD_V0)
+nvd0_disp_main_scanoutpos(NV50_DISP_MTHD_V0)
 {
        const u32 total  = nv_rd32(priv, 0x640414 + (head * 0x300));
        const u32 blanke = nv_rd32(priv, 0x64041c + (head * 0x300));
@@ -656,7 +658,7 @@ nvd0_disp_base_scanoutpos(NV50_DISP_MTHD_V0)
 }
 
 static int
-nvd0_disp_base_init(struct nouveau_object *object)
+nvd0_disp_main_init(struct nouveau_object *object)
 {
        struct nv50_disp_priv *priv = (void *)object->engine;
        struct nv50_disp_base *base = (void *)object;
@@ -725,7 +727,7 @@ nvd0_disp_base_init(struct nouveau_object *object)
 }
 
 static int
-nvd0_disp_base_fini(struct nouveau_object *object, bool suspend)
+nvd0_disp_main_fini(struct nouveau_object *object, bool suspend)
 {
        struct nv50_disp_priv *priv = (void *)object->engine;
        struct nv50_disp_base *base = (void *)object;
@@ -737,25 +739,25 @@ nvd0_disp_base_fini(struct nouveau_object *object, bool suspend)
 }
 
 struct nouveau_ofuncs
-nvd0_disp_base_ofuncs = {
-       .ctor = nv50_disp_base_ctor,
-       .dtor = nv50_disp_base_dtor,
-       .init = nvd0_disp_base_init,
-       .fini = nvd0_disp_base_fini,
-       .mthd = nv50_disp_base_mthd,
+nvd0_disp_main_ofuncs = {
+       .ctor = nv50_disp_main_ctor,
+       .dtor = nv50_disp_main_dtor,
+       .init = nvd0_disp_main_init,
+       .fini = nvd0_disp_main_fini,
+       .mthd = nv50_disp_main_mthd,
        .ntfy = nouveau_disp_ntfy,
 };
 
 static struct nouveau_oclass
-nvd0_disp_base_oclass[] = {
-       { GF110_DISP, &nvd0_disp_base_ofuncs },
+nvd0_disp_main_oclass[] = {
+       { GF110_DISP, &nvd0_disp_main_ofuncs },
        {}
 };
 
 static struct nouveau_oclass
 nvd0_disp_sclass[] = {
-       { GF110_DISP_CORE_CHANNEL_DMA, &nvd0_disp_mast_ofuncs.base },
-       { GF110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_sync_ofuncs.base },
+       { GF110_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
+       { GF110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
        { GF110_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
        { GF110_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
        { GF110_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
@@ -1055,6 +1057,9 @@ nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head)
 
                if (nvkm_output_dp_train(outp, pclk, true))
                        ERR("link not trained before attach\n");
+       } else {
+               if (priv->sor.magic)
+                       priv->sor.magic(outp);
        }
 
        exec_clkcmp(priv, head, 0, pclk, &conf);
@@ -1063,10 +1068,18 @@ nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head)
                addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800;
                data = 0x00000000;
        } else {
-               if (outp->info.type == DCB_OUTPUT_DP)
-                       nvd0_disp_intr_unk2_2_tu(priv, head, &outp->info);
                addr = 0x612300 + (ffs(outp->info.or) - 1) * 0x800;
                data = (conf & 0x0100) ? 0x00000101 : 0x00000000;
+               switch (outp->info.type) {
+               case DCB_OUTPUT_TMDS:
+                       nv_mask(priv, addr, 0x007c0000, 0x00280000);
+                       break;
+               case DCB_OUTPUT_DP:
+                       nvd0_disp_intr_unk2_2_tu(priv, head, &outp->info);
+                       break;
+               default:
+                       break;
+               }
        }
 
        nv_mask(priv, addr, 0x00000707, data);
@@ -1259,7 +1272,7 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       nv_engine(priv)->sclass = nvd0_disp_base_oclass;
+       nv_engine(priv)->sclass = nvd0_disp_main_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nvd0_disp_intr;
        INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
@@ -1292,9 +1305,9 @@ nvd0_disp_oclass = &(struct nv50_disp_impl) {
        },
        .base.vblank = &nvd0_disp_vblank_func,
        .base.outp =  nvd0_disp_outp_sclass,
-       .mthd.core = &nvd0_disp_mast_mthd_chan,
-       .mthd.base = &nvd0_disp_sync_mthd_chan,
+       .mthd.core = &nvd0_disp_core_mthd_chan,
+       .mthd.base = &nvd0_disp_base_mthd_chan,
        .mthd.ovly = &nvd0_disp_ovly_mthd_chan,
        .mthd.prev = -0x020000,
-       .head.scanoutpos = nvd0_disp_base_scanoutpos,
+       .head.scanoutpos = nvd0_disp_main_scanoutpos,
 }.base.base;
index db144b2cf06bd7a98df12c59a718a608ba5ef27b..55debec7e68f7d7b1009f80864dd3833ae8674d1 100644 (file)
@@ -34,7 +34,7 @@
  ******************************************************************************/
 
 static const struct nv50_disp_mthd_list
-nve0_disp_mast_mthd_head = {
+nve0_disp_core_mthd_head = {
        .mthd = 0x0300,
        .addr = 0x000300,
        .data = {
@@ -113,15 +113,15 @@ nve0_disp_mast_mthd_head = {
 };
 
 const struct nv50_disp_mthd_chan
-nve0_disp_mast_mthd_chan = {
+nve0_disp_core_mthd_chan = {
        .name = "Core",
        .addr = 0x000000,
        .data = {
-               { "Global", 1, &nvd0_disp_mast_mthd_base },
-               {    "DAC", 3, &nvd0_disp_mast_mthd_dac  },
-               {    "SOR", 8, &nvd0_disp_mast_mthd_sor  },
-               {   "PIOR", 4, &nvd0_disp_mast_mthd_pior },
-               {   "HEAD", 4, &nve0_disp_mast_mthd_head },
+               { "Global", 1, &nvd0_disp_core_mthd_base },
+               {    "DAC", 3, &nvd0_disp_core_mthd_dac  },
+               {    "SOR", 8, &nvd0_disp_core_mthd_sor  },
+               {   "PIOR", 4, &nvd0_disp_core_mthd_pior },
+               {   "HEAD", 4, &nve0_disp_core_mthd_head },
                {}
        }
 };
@@ -200,8 +200,8 @@ nve0_disp_ovly_mthd_chan = {
 
 static struct nouveau_oclass
 nve0_disp_sclass[] = {
-       { GK104_DISP_CORE_CHANNEL_DMA, &nvd0_disp_mast_ofuncs.base },
-       { GK104_DISP_BASE_CHANNEL_DMA, &nvd0_disp_sync_ofuncs.base },
+       { GK104_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
+       { GK104_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
        { GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
        { GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
        { GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
@@ -209,8 +209,8 @@ nve0_disp_sclass[] = {
 };
 
 static struct nouveau_oclass
-nve0_disp_base_oclass[] = {
-       { GK104_DISP, &nvd0_disp_base_ofuncs },
+nve0_disp_main_oclass[] = {
+       { GK104_DISP, &nvd0_disp_main_ofuncs },
        {}
 };
 
@@ -237,7 +237,7 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       nv_engine(priv)->sclass = nve0_disp_base_oclass;
+       nv_engine(priv)->sclass = nve0_disp_main_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nvd0_disp_intr;
        INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
@@ -264,9 +264,9 @@ nve0_disp_oclass = &(struct nv50_disp_impl) {
        },
        .base.vblank = &nvd0_disp_vblank_func,
        .base.outp =  nvd0_disp_outp_sclass,
-       .mthd.core = &nve0_disp_mast_mthd_chan,
-       .mthd.base = &nvd0_disp_sync_mthd_chan,
+       .mthd.core = &nve0_disp_core_mthd_chan,
+       .mthd.base = &nvd0_disp_base_mthd_chan,
        .mthd.ovly = &nve0_disp_ovly_mthd_chan,
        .mthd.prev = -0x020000,
-       .head.scanoutpos = nvd0_disp_base_scanoutpos,
+       .head.scanoutpos = nvd0_disp_main_scanoutpos,
 }.base.base;
index 402d7d67d806fa0cd81dd61c758c6e868dc4cf90..3e7e2d28744c48b8e6f725e19bbbf7343013f452 100644 (file)
@@ -35,8 +35,8 @@
 
 static struct nouveau_oclass
 nvf0_disp_sclass[] = {
-       { GK110_DISP_CORE_CHANNEL_DMA, &nvd0_disp_mast_ofuncs.base },
-       { GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_sync_ofuncs.base },
+       { GK110_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
+       { GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
        { GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
        { GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
        { GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
@@ -44,8 +44,8 @@ nvf0_disp_sclass[] = {
 };
 
 static struct nouveau_oclass
-nvf0_disp_base_oclass[] = {
-       { GK110_DISP, &nvd0_disp_base_ofuncs },
+nvf0_disp_main_oclass[] = {
+       { GK110_DISP, &nvd0_disp_main_ofuncs },
        {}
 };
 
@@ -72,7 +72,7 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       nv_engine(priv)->sclass = nvf0_disp_base_oclass;
+       nv_engine(priv)->sclass = nvf0_disp_main_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nvd0_disp_intr;
        INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
@@ -99,9 +99,9 @@ nvf0_disp_oclass = &(struct nv50_disp_impl) {
        },
        .base.vblank = &nvd0_disp_vblank_func,
        .base.outp =  nvd0_disp_outp_sclass,
-       .mthd.core = &nve0_disp_mast_mthd_chan,
-       .mthd.base = &nvd0_disp_sync_mthd_chan,
+       .mthd.core = &nve0_disp_core_mthd_chan,
+       .mthd.base = &nvd0_disp_base_mthd_chan,
        .mthd.ovly = &nve0_disp_ovly_mthd_chan,
        .mthd.prev = -0x020000,
-       .head.scanoutpos = nvd0_disp_base_scanoutpos,
+       .head.scanoutpos = nvd0_disp_main_scanoutpos,
 }.base.base;
index a5ff00a9cedc044ee83d9ae343a0ed1461a38f3e..bbd9b6fdc90f1744ccce55375afa66f0f320fef0 100644 (file)
@@ -85,7 +85,10 @@ nvkm_output_create_(struct nouveau_object *parent,
            dcbE->sorconf.link : 0, dcbE->connector, dcbE->i2c_index,
            dcbE->bus, dcbE->heads);
 
-       outp->port = i2c->find(i2c, outp->info.i2c_index);
+       if (outp->info.type != DCB_OUTPUT_DP)
+               outp->port = i2c->find(i2c, NV_I2C_PORT(outp->info.i2c_index));
+       else
+               outp->port = i2c->find(i2c, NV_I2C_AUX(outp->info.i2c_index));
        outp->edid = outp->port;
 
        data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE);
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sorgm204.c b/drivers/gpu/drm/nouveau/core/engine/disp/sorgm204.c
new file mode 100644 (file)
index 0000000..0b4fad3
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <core/os.h>
+
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/dp.h>
+#include <subdev/bios/init.h>
+#include <subdev/timer.h>
+
+#include "nv50.h"
+
+static inline u32
+gm204_sor_soff(struct nvkm_output_dp *outp)
+{
+       return (ffs(outp->base.info.or) - 1) * 0x800;
+}
+
+static inline u32
+gm204_sor_loff(struct nvkm_output_dp *outp)
+{
+       return gm204_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
+}
+
+void
+gm204_sor_magic(struct nvkm_output *outp)
+{
+       struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
+       const u32 soff = outp->or * 0x100;
+       const u32 data = outp->or + 1;
+       if (outp->info.sorconf.link & 1)
+               nv_mask(priv, 0x612308 + soff, 0x0000001f, 0x00000000 | data);
+       if (outp->info.sorconf.link & 2)
+               nv_mask(priv, 0x612388 + soff, 0x0000001f, 0x00000010 | data);
+}
+
+static inline u32
+gm204_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
+{
+       return lane * 0x08;
+}
+
+static int
+gm204_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
+{
+       struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
+       const u32 soff = gm204_sor_soff(outp);
+       const u32 data = 0x01010101 * pattern;
+       if (outp->base.info.sorconf.link & 1)
+               nv_mask(priv, 0x61c110 + soff, 0x0f0f0f0f, data);
+       else
+               nv_mask(priv, 0x61c12c + soff, 0x0f0f0f0f, data);
+       return 0;
+}
+
+static int
+gm204_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
+{
+       struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
+       const u32 soff = gm204_sor_soff(outp);
+       const u32 loff = gm204_sor_loff(outp);
+       u32 mask = 0, i;
+
+       for (i = 0; i < nr; i++)
+               mask |= 1 << (gm204_sor_dp_lane_map(priv, i) >> 3);
+
+       nv_mask(priv, 0x61c130 + loff, 0x0000000f, mask);
+       nv_mask(priv, 0x61c034 + soff, 0x80000000, 0x80000000);
+       nv_wait(priv, 0x61c034 + soff, 0x80000000, 0x00000000);
+       return 0;
+}
+
+static int
+gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
+{
+       struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
+       struct nouveau_bios *bios = nouveau_bios(priv);
+       const u32 shift = gm204_sor_dp_lane_map(priv, ln);
+       const u32 loff = gm204_sor_loff(outp);
+       u32 addr, data[4];
+       u8  ver, hdr, cnt, len;
+       struct nvbios_dpout info;
+       struct nvbios_dpcfg ocfg;
+
+       addr = nvbios_dpout_match(bios, outp->base.info.hasht,
+                                       outp->base.info.hashm,
+                                &ver, &hdr, &cnt, &len, &info);
+       if (!addr)
+               return -ENODEV;
+
+       addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe,
+                                &ver, &hdr, &cnt, &len, &ocfg);
+       if (!addr)
+               return -EINVAL;
+
+       data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
+       data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
+       data[2] = nv_rd32(priv, 0x61c130 + loff);
+       if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
+               data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
+       nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
+       nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
+       nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8));
+       data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift);
+       nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift));
+       return 0;
+}
+
+struct nvkm_output_dp_impl
+gm204_sor_dp_impl = {
+       .base.base.handle = DCB_OUTPUT_DP,
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = _nvkm_output_dp_ctor,
+               .dtor = _nvkm_output_dp_dtor,
+               .init = _nvkm_output_dp_init,
+               .fini = _nvkm_output_dp_fini,
+       },
+       .pattern = gm204_sor_dp_pattern,
+       .lnk_pwr = gm204_sor_dp_lnk_pwr,
+       .lnk_ctl = nvd0_sor_dp_lnk_ctl,
+       .drv_ctl = gm204_sor_dp_drv_ctl,
+};
index 7b7bbc3e459e4eceafd2a476cca3a65a21254cdc..fdab2939070c8e441ce54c03178566bee695e6ed 100644 (file)
@@ -60,7 +60,7 @@ nvd0_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
        return 0;
 }
 
-static int
+int
 nvd0_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
 {
        struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
index 3fc4f0b0eacae1b86c0b3507f10a801a24ae185b..19f5f652296204e72c412c1b627a7ae452cce75a 100644 (file)
@@ -51,6 +51,7 @@ nvd0_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
                case GK104_DISP_CORE_CHANNEL_DMA:
                case GK110_DISP_CORE_CHANNEL_DMA:
                case GM107_DISP_CORE_CHANNEL_DMA:
+               case GM204_DISP_CORE_CHANNEL_DMA:
                case GF110_DISP_BASE_CHANNEL_DMA:
                case GK104_DISP_BASE_CHANNEL_DMA:
                case GK110_DISP_BASE_CHANNEL_DMA:
index d2f0fd39c1453c82e905c42ecf00551df7125f69..fc9ef663f25ac0f3368b0c694091505796ff7d9c 100644 (file)
@@ -792,7 +792,7 @@ nve0_fifo_intr_fault(struct nve0_fifo_priv *priv, int unit)
        nouveau_engctx_put(engctx);
 }
 
-static const struct nouveau_bitfield nve0_fifo_pbdma_intr[] = {
+static const struct nouveau_bitfield nve0_fifo_pbdma_intr_0[] = {
        { 0x00000001, "MEMREQ" },
        { 0x00000002, "MEMACK_TIMEOUT" },
        { 0x00000004, "MEMACK_EXTRA" },
@@ -827,9 +827,10 @@ static const struct nouveau_bitfield nve0_fifo_pbdma_intr[] = {
 };
 
 static void
-nve0_fifo_intr_pbdma(struct nve0_fifo_priv *priv, int unit)
+nve0_fifo_intr_pbdma_0(struct nve0_fifo_priv *priv, int unit)
 {
-       u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000));
+       u32 mask = nv_rd32(priv, 0x04010c + (unit * 0x2000));
+       u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000)) & mask;
        u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
        u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
        u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff;
@@ -840,11 +841,12 @@ nve0_fifo_intr_pbdma(struct nve0_fifo_priv *priv, int unit)
        if (stat & 0x00800000) {
                if (!nve0_fifo_swmthd(priv, chid, mthd, data))
                        show &= ~0x00800000;
+               nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
        }
 
        if (show) {
                nv_error(priv, "PBDMA%d:", unit);
-               nouveau_bitfield_print(nve0_fifo_pbdma_intr, show);
+               nouveau_bitfield_print(nve0_fifo_pbdma_intr_0, show);
                pr_cont("\n");
                nv_error(priv,
                         "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
@@ -853,10 +855,37 @@ nve0_fifo_intr_pbdma(struct nve0_fifo_priv *priv, int unit)
                         subc, mthd, data);
        }
 
-       nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
        nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
 }
 
+static const struct nouveau_bitfield nve0_fifo_pbdma_intr_1[] = {
+       { 0x00000001, "HCE_RE_ILLEGAL_OP" },
+       { 0x00000002, "HCE_RE_ALIGNB" },
+       { 0x00000004, "HCE_PRIV" },
+       { 0x00000008, "HCE_ILLEGAL_MTHD" },
+       { 0x00000010, "HCE_ILLEGAL_CLASS" },
+       {}
+};
+
+static void
+nve0_fifo_intr_pbdma_1(struct nve0_fifo_priv *priv, int unit)
+{
+       u32 mask = nv_rd32(priv, 0x04014c + (unit * 0x2000));
+       u32 stat = nv_rd32(priv, 0x040148 + (unit * 0x2000)) & mask;
+       u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff;
+
+       if (stat) {
+               nv_error(priv, "PBDMA%d:", unit);
+               nouveau_bitfield_print(nve0_fifo_pbdma_intr_1, stat);
+               pr_cont("\n");
+               nv_error(priv, "PBDMA%d: ch %d %08x %08x\n", unit, chid,
+                        nv_rd32(priv, 0x040150 + (unit * 0x2000)),
+                        nv_rd32(priv, 0x040154 + (unit * 0x2000)));
+       }
+
+       nv_wr32(priv, 0x040148 + (unit * 0x2000), stat);
+}
+
 static void
 nve0_fifo_intr_runlist(struct nve0_fifo_priv *priv)
 {
@@ -939,7 +968,8 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
                u32 mask = nv_rd32(priv, 0x0025a0);
                while (mask) {
                        u32 unit = __ffs(mask);
-                       nve0_fifo_intr_pbdma(priv, unit);
+                       nve0_fifo_intr_pbdma_0(priv, unit);
+                       nve0_fifo_intr_pbdma_1(priv, unit);
                        nv_wr32(priv, 0x0025a0, (1 << unit));
                        mask &= ~(1 << unit);
                }
@@ -1022,6 +1052,12 @@ nve0_fifo_init(struct nouveau_object *object)
                nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
        }
 
+       /* PBDMA[n].HCE */
+       for (i = 0; i < priv->spoon_nr; i++) {
+               nv_wr32(priv, 0x040148 + (i * 0x2000), 0xffffffff); /* INTR */
+               nv_wr32(priv, 0x04014c + (i * 0x2000), 0xffffffff); /* INTREN */
+       }
+
        nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
 
        nv_wr32(priv, 0x002100, 0xffffffff);
index 30fd1dc64f9307603e137c43d5f6bf0e76e05d4f..17251e4b9e8647c7dd52b4bc7eebbe052a485259 100644 (file)
@@ -1557,7 +1557,7 @@ nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                    nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) ||
                    nvc0_graph_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) ||
                    nvc0_graph_ctor_fw(priv, "fuc41ad", &priv->fuc41ad))
-                       return -EINVAL;
+                       return -ENODEV;
                priv->firmware = true;
        }
 
index 1d9d893929bb3486b1c35229ac238ea89a883dbc..2ec2e50d3676607208ac8c1e5c5e58fc7ca9596a 100644 (file)
@@ -16,6 +16,7 @@ enum nv_subdev_type {
         * to during POST.
         */
        NVDEV_SUBDEV_DEVINIT,
+       NVDEV_SUBDEV_IBUS,
        NVDEV_SUBDEV_GPIO,
        NVDEV_SUBDEV_I2C,
        NVDEV_SUBDEV_DEVINIT_LAST = NVDEV_SUBDEV_I2C,
@@ -31,7 +32,6 @@ enum nv_subdev_type {
        NVDEV_SUBDEV_TIMER,
        NVDEV_SUBDEV_FB,
        NVDEV_SUBDEV_LTC,
-       NVDEV_SUBDEV_IBUS,
        NVDEV_SUBDEV_INSTMEM,
        NVDEV_SUBDEV_VM,
        NVDEV_SUBDEV_BAR,
@@ -92,6 +92,7 @@ struct nouveau_device {
                GM100    = 0x110,
        } card_type;
        u32 chipset;
+       u8  chiprev;
        u32 crystal;
 
        struct nouveau_oclass *oclass[NVDEV_SUBDEV_NR];
@@ -158,6 +159,12 @@ nv_device_is_pci(struct nouveau_device *device)
        return device->pdev != NULL;
 }
 
+static inline bool
+nv_device_is_cpu_coherent(struct nouveau_device *device)
+{
+       return (!IS_ENABLED(CONFIG_ARM) && nv_device_is_pci(device));
+}
+
 static inline struct device *
 nv_device_base(struct nouveau_device *device)
 {
index ceb67d77087522cba3394837a7a2e18336db2872..d22a59138a9b5fd29af066eb885726e5c0ae84f0 100644 (file)
@@ -23,11 +23,6 @@ void nouveau_handle_destroy(struct nouveau_handle *);
 int  nouveau_handle_init(struct nouveau_handle *);
 int  nouveau_handle_fini(struct nouveau_handle *, bool suspend);
 
-int  nouveau_handle_new(struct nouveau_object *, u32 parent, u32 handle,
-                       u16 oclass, void *data, u32 size,
-                       struct nouveau_object **);
-int  nouveau_handle_del(struct nouveau_object *, u32 parent, u32 handle);
-
 struct nouveau_object *
 nouveau_handle_ref(struct nouveau_object *, u32 name);
 
index d7039482d6fd6cb035cba3ba4bb13cfd4a120d60..2e2afa502c990228b23f0227f69c0ade14354174 100644 (file)
@@ -203,21 +203,4 @@ nv_memcmp(void *obj, u32 addr, const char *str, u32 len)
        return 0;
 }
 
-#include <core/handle.h>
-
-static inline int
-nouveau_object_new(struct nouveau_object *client, u32 parent, u32 handle,
-                  u16 oclass, void *data, u32 size,
-                  struct nouveau_object **pobject)
-{
-       return nouveau_handle_new(client, parent, handle, oclass,
-                                 data, size, pobject);
-}
-
-static inline int
-nouveau_object_del(struct nouveau_object *client, u32 parent, u32 handle)
-{
-       return nouveau_handle_del(client, parent, handle);
-}
-
 #endif
index 7a64f347b385d18d60eba08d58c969c0937d5853..fc307f1317ffaf7836edcd286cc3f8307b036973 100644 (file)
@@ -31,5 +31,6 @@ extern struct nouveau_oclass *nvd0_disp_oclass;
 extern struct nouveau_oclass *nve0_disp_oclass;
 extern struct nouveau_oclass *nvf0_disp_oclass;
 extern struct nouveau_oclass *gm107_disp_oclass;
+extern struct nouveau_oclass *gm204_disp_oclass;
 
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0203.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0203.h
new file mode 100644 (file)
index 0000000..1f84d36
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __NVBIOS_M0203_H__
+#define __NVBIOS_M0203_H__
+
+struct nvbios_M0203T {
+#define M0203T_TYPE_RAMCFG 0x00
+       u8  type;
+       u16 pointer;
+};
+
+u32 nvbios_M0203Te(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u32 nvbios_M0203Tp(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+                  struct nvbios_M0203T *);
+
+struct nvbios_M0203E {
+#define M0203E_TYPE_DDR2  0x0
+#define M0203E_TYPE_DDR3  0x1
+#define M0203E_TYPE_GDDR3 0x2
+#define M0203E_TYPE_GDDR5 0x3
+#define M0203E_TYPE_SKIP  0xf
+       u8 type;
+       u8 strap;
+       u8 group;
+};
+
+u32 nvbios_M0203Ee(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_M0203Ep(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
+                  struct nvbios_M0203E *);
+u32 nvbios_M0203Em(struct nouveau_bios *, u8 ramcfg, u8 *ver, u8 *hdr,
+                  struct nvbios_M0203E *);
+
+#endif
index 10b57a19a7decb7f6a5604ed6ce5befe4ecd18e9..c9bb112895aff3ea8b86eaa6237040ea946b1b96 100644 (file)
@@ -4,11 +4,14 @@
 struct nouveau_bios;
 
 enum dcb_i2c_type {
-       DCB_I2C_NV04_BIT = 0,
-       DCB_I2C_NV4E_BIT = 4,
-       DCB_I2C_NVIO_BIT = 5,
-       DCB_I2C_NVIO_AUX = 6,
-       DCB_I2C_UNUSED = 0xff
+       /* matches bios type field prior to ccb 4.1 */
+       DCB_I2C_NV04_BIT = 0x00,
+       DCB_I2C_NV4E_BIT = 0x04,
+       DCB_I2C_NVIO_BIT = 0x05,
+       DCB_I2C_NVIO_AUX = 0x06,
+       /* made up - mostly */
+       DCB_I2C_PMGR     = 0x80,
+       DCB_I2C_UNUSED   = 0xff
 };
 
 struct dcb_i2c_entry {
@@ -16,6 +19,7 @@ struct dcb_i2c_entry {
        u8 drive;
        u8 sense;
        u8 share;
+       u8 auxch;
 };
 
 u16 dcb_i2c_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/image.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/image.h
new file mode 100644 (file)
index 0000000..3348b45
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __NVBIOS_IMAGE_H__
+#define __NVBIOS_IMAGE_H__
+
+struct nvbios_image {
+       u32  base;
+       u32  size;
+       u8   type;
+       bool last;
+};
+
+bool nvbios_image(struct nouveau_bios *, int, struct nvbios_image *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/npde.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/npde.h
new file mode 100644 (file)
index 0000000..b18413d
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __NVBIOS_NPDE_H__
+#define __NVBIOS_NPDE_H__
+
+struct nvbios_npdeT {
+       u32 image_size;
+       bool last;
+};
+
+u32 nvbios_npdeTe(struct nouveau_bios *, u32);
+u32 nvbios_npdeTp(struct nouveau_bios *, u32, struct nvbios_npdeT *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pcir.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/pcir.h
new file mode 100644 (file)
index 0000000..3d634a0
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __NVBIOS_PCIR_H__
+#define __NVBIOS_PCIR_H__
+
+struct nvbios_pcirT {
+       u16 vendor_id;
+       u16 device_id;
+       u8  class_code[3];
+       u32 image_size;
+       u16 image_rev;
+       u8  image_type;
+       bool last;
+};
+
+u32 nvbios_pcirTe(struct nouveau_bios *, u32, u8 *ver, u16 *hdr);
+u32 nvbios_pcirTp(struct nouveau_bios *, u32, u8 *ver, u16 *hdr,
+                 struct nvbios_pcirT *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pmu.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/pmu.h
new file mode 100644 (file)
index 0000000..9de593d
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __NVBIOS_PMU_H__
+#define __NVBIOS_PMU_H__
+
+struct nvbios_pmuT {
+};
+
+u32 nvbios_pmuTe(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u32 nvbios_pmuTp(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+                struct nvbios_pmuT *);
+
+struct nvbios_pmuE {
+       u8  type;
+       u32 data;
+};
+
+u32 nvbios_pmuEe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_pmuEp(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
+                struct nvbios_pmuE *);
+
+struct nvbios_pmuR {
+       u32 boot_addr_pmu;
+       u32 boot_addr;
+       u32 boot_size;
+       u32 code_addr_pmu;
+       u32 code_addr;
+       u32 code_size;
+       u32 init_addr_pmu;
+
+       u32 data_addr_pmu;
+       u32 data_addr;
+       u32 data_size;
+       u32 args_addr_pmu;
+};
+
+bool nvbios_pmuRm(struct nouveau_bios *, u8 type, struct nvbios_pmuR *);
+
+#endif
index a685bbd045680529e33d6d54e78a0359ab61c0cb..4a0e0ceb41baadfc7da271ffc11978c7426d8a17 100644 (file)
@@ -43,8 +43,9 @@ struct nvbios_ramcfg {
                        unsigned ramcfg_10_02_08:1;
                        unsigned ramcfg_10_02_10:1;
                        unsigned ramcfg_10_02_20:1;
-                       unsigned ramcfg_10_02_40:1;
+                       unsigned ramcfg_10_DLLoff:1;
                        unsigned ramcfg_10_03_0f:4;
+                       unsigned ramcfg_10_04_01:1;
                        unsigned ramcfg_10_05:8;
                        unsigned ramcfg_10_06:8;
                        unsigned ramcfg_10_07:8;
@@ -95,9 +96,29 @@ struct nvbios_ramcfg {
        union {
                struct {
                        unsigned timing_10_WR:8;
+                       unsigned timing_10_WTR:8;
                        unsigned timing_10_CL:8;
+                       unsigned timing_10_RC:8;
+                       /*empty: 4 */
+                       unsigned timing_10_RFC:8;        /* Byte 5 */
+                       /*empty: 6 */
+                       unsigned timing_10_RAS:8;        /* Byte 7 */
+                       /*empty: 8 */
+                       unsigned timing_10_RP:8;         /* Byte 9 */
+                       unsigned timing_10_RCDRD:8;
+                       unsigned timing_10_RCDWR:8;
+                       unsigned timing_10_RRD:8;
+                       unsigned timing_10_13:8;
                        unsigned timing_10_ODT:3;
+                       /* empty: 15 */
+                       unsigned timing_10_16:8;
+                       /* empty: 17 */
+                       unsigned timing_10_18:8;
                        unsigned timing_10_CWL:8;
+                       unsigned timing_10_20:8;
+                       unsigned timing_10_21:8;
+                       /* empty: 22, 23 */
+                       unsigned timing_10_24:8;
                };
                struct {
                        unsigned timing_20_2e_03:2;
index e292271a84e40384b4fd92d4a25c2f2fec025e9d..e007a9d44683fb40b3922e797d6302aabd18a9a2 100644 (file)
@@ -30,5 +30,6 @@ extern struct nouveau_oclass *nva3_devinit_oclass;
 extern struct nouveau_oclass *nvaf_devinit_oclass;
 extern struct nouveau_oclass *nvc0_devinit_oclass;
 extern struct nouveau_oclass *gm107_devinit_oclass;
+extern struct nouveau_oclass *gm204_devinit_oclass;
 
 #endif
index 1b937c2c25ae2e43a6594c203ad989294028a57c..d94ccacb40bf1ae60081e9458f6ffdaf14d36bb9 100644 (file)
@@ -8,6 +8,8 @@
 #include <subdev/bios/i2c.h>
 
 #define NV_I2C_PORT(n)    (0x00 + (n))
+#define NV_I2C_AUX(n)     (0x10 + (n))
+#define NV_I2C_EXT(n)     (0x20 + (n))
 #define NV_I2C_DEFAULT(n) (0x80 + (n))
 
 #define NV_I2C_TYPE_DCBI2C(n) (0x0000 | (n))
@@ -89,6 +91,7 @@ extern struct nouveau_oclass *nv94_i2c_oclass;
 extern struct nouveau_oclass *nvd0_i2c_oclass;
 extern struct nouveau_oclass *gf117_i2c_oclass;
 extern struct nouveau_oclass *nve0_i2c_oclass;
+extern struct nouveau_oclass *gm204_i2c_oclass;
 
 static inline int
 nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg)
index bf3d1f6113331a72045c7f154eadb04c64ebc9f6..f2427bf5aeed70e14bff97d84612ae81c62fdd30 100644 (file)
@@ -48,6 +48,8 @@ void nouveau_memx_wait(struct nouveau_memx *,
                       u32 addr, u32 mask, u32 data, u32 nsec);
 void nouveau_memx_nsec(struct nouveau_memx *, u32 nsec);
 void nouveau_memx_wait_vblank(struct nouveau_memx *);
+void nouveau_memx_train(struct nouveau_memx *);
+int  nouveau_memx_train_result(struct nouveau_pwr *, u32 *, int);
 void nouveau_memx_block(struct nouveau_memx *);
 void nouveau_memx_unblock(struct nouveau_memx *);
 
index 820b62ffd75b286e084fb915a22969e8ffdb5d15..67db5e58880d3df2ef503fbe9a5f14d6401da802 100644 (file)
@@ -52,6 +52,7 @@ int  _nouveau_volt_init(struct nouveau_object *);
 #define _nouveau_volt_fini _nouveau_subdev_fini
 
 extern struct nouveau_oclass nv40_volt_oclass;
+extern struct nouveau_oclass gk20a_volt_oclass;
 
 int nouveau_voltgpio_init(struct nouveau_volt *);
 int nouveau_voltgpio_get(struct nouveau_volt *);
index ccfa21d72ddc950e3a2f583f7e9194382e0a08ed..bdd05ee7ec72ea671a8413b6da15d0c33cd03dbd 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/power_supply.h>
 #include <linux/clk.h>
+#include <linux/regulator/consumer.h>
 
 #include <asm/unaligned.h>
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/M0203.c b/drivers/gpu/drm/nouveau/core/subdev/bios/M0203.c
new file mode 100644 (file)
index 0000000..28906b1
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/M0203.h>
+
+u32
+nvbios_M0203Te(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+       struct bit_entry bit_M;
+       u32 data = 0x00000000;
+
+       if (!bit_entry(bios, 'M', &bit_M)) {
+               if (bit_M.version == 2 && bit_M.length > 0x04)
+                       data = nv_ro16(bios, bit_M.offset + 0x03);
+               if (data) {
+                       *ver = nv_ro08(bios, data + 0x00);
+                       switch (*ver) {
+                       case 0x10:
+                               *hdr = nv_ro08(bios, data + 0x01);
+                               *len = nv_ro08(bios, data + 0x02);
+                               *cnt = nv_ro08(bios, data + 0x03);
+                               return data;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       return 0x00000000;
+}
+
+u32
+nvbios_M0203Tp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+              struct nvbios_M0203T *info)
+{
+       u32 data = nvbios_M0203Te(bios, ver, hdr, cnt, len);
+       memset(info, 0x00, sizeof(*info));
+       switch (!!data * *ver) {
+       case 0x10:
+               info->type    = nv_ro08(bios, data + 0x04);
+               info->pointer = nv_ro16(bios, data + 0x05);
+               break;
+       default:
+               break;
+       }
+       return data;
+}
+
+u32
+nvbios_M0203Ee(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr)
+{
+       u8  cnt, len;
+       u32 data = nvbios_M0203Te(bios, ver, hdr, &cnt, &len);
+       if (data && idx < cnt) {
+               data = data + *hdr + idx * len;
+               *hdr = len;
+               return data;
+       }
+       return 0x00000000;
+}
+
+u32
+nvbios_M0203Ep(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
+              struct nvbios_M0203E *info)
+{
+       u32 data = nvbios_M0203Ee(bios, idx, ver, hdr);
+       memset(info, 0x00, sizeof(*info));
+       switch (!!data * *ver) {
+       case 0x10:
+               info->type  = (nv_ro08(bios, data + 0x00) & 0x0f) >> 0;
+               info->strap = (nv_ro08(bios, data + 0x00) & 0xf0) >> 4;
+               info->group = (nv_ro08(bios, data + 0x01) & 0x0f) >> 0;
+               return data;
+       default:
+               break;
+       }
+       return 0x00000000;
+}
+
+u32
+nvbios_M0203Em(struct nouveau_bios *bios, u8 ramcfg, u8 *ver, u8 *hdr,
+              struct nvbios_M0203E *info)
+{
+       struct nvbios_M0203T M0203T;
+       u8  cnt, len, idx = 0xff;
+       u32 data;
+
+       if (!nvbios_M0203Tp(bios, ver, hdr, &cnt, &len, &M0203T)) {
+               nv_warn(bios, "M0203T not found\n");
+               return 0x00000000;
+       }
+
+       while ((data = nvbios_M0203Ep(bios, ++idx, ver, hdr, info))) {
+               switch (M0203T.type) {
+               case M0203T_TYPE_RAMCFG:
+                       if (info->strap != ramcfg)
+                               continue;
+                       return data;
+               default:
+                       nv_warn(bios, "M0203T type %02x\n", M0203T.type);
+                       return 0x00000000;
+               }
+       }
+
+       return data;
+}
index d45704a2c2df5b6aa1b95eda83d990995955e4c5..7df3a273553db24a2d608d318d1421f7f26f443a 100644 (file)
@@ -31,6 +31,8 @@
 #include <subdev/bios/bmp.h>
 #include <subdev/bios/bit.h>
 
+#include "priv.h"
+
 u8
 nvbios_checksum(const u8 *data, int size)
 {
@@ -56,362 +58,21 @@ nvbios_findstr(const u8 *data, int size, const char *str, int len)
        return 0;
 }
 
-#if defined(__powerpc__)
-static void
-nouveau_bios_shadow_of(struct nouveau_bios *bios)
+int
+nvbios_extend(struct nouveau_bios *bios, u32 length)
 {
-       struct pci_dev *pdev = nv_device(bios)->pdev;
-       struct device_node *dn;
-       const u32 *data;
-       int size;
-
-       dn = pci_device_to_OF_node(pdev);
-       if (!dn) {
-               nv_info(bios, "Unable to get the OF node\n");
-               return;
-       }
-
-       data = of_get_property(dn, "NVDA,BMP", &size);
-       if (data && size) {
-               bios->size = size;
-               bios->data = kmalloc(bios->size, GFP_KERNEL);
-               if (bios->data)
-                       memcpy(bios->data, data, size);
-       }
-}
-#endif
-
-static void
-nouveau_bios_shadow_pramin(struct nouveau_bios *bios)
-{
-       struct nouveau_device *device = nv_device(bios);
-       u64 addr = 0;
-       u32 bar0 = 0;
-       int i;
-
-       if (device->card_type >= NV_50) {
-               if (device->card_type >= NV_C0 && device->card_type < GM100) {
-                       if (nv_rd32(bios, 0x022500) & 0x00000001)
-                               return;
-               } else
-               if (device->card_type >= GM100) {
-                       if (nv_rd32(bios, 0x021c04) & 0x00000001)
-                               return;
-               }
-
-               addr = nv_rd32(bios, 0x619f04);
-               if (!(addr & 0x00000008)) {
-                       nv_debug(bios, "... not enabled\n");
-                       return;
+       if (bios->size < length) {
+               u8 *prev = bios->data;
+               if (!(bios->data = kmalloc(length, GFP_KERNEL))) {
+                       bios->data = prev;
+                       return -ENOMEM;
                }
-               if ( (addr & 0x00000003) != 1) {
-                       nv_debug(bios, "... not in vram\n");
-                       return;
-               }
-
-               addr = (addr & 0xffffff00) << 8;
-               if (!addr) {
-                       addr  = (u64)nv_rd32(bios, 0x001700) << 16;
-                       addr += 0xf0000;
-               }
-
-               bar0 = nv_mask(bios, 0x001700, 0xffffffff, addr >> 16);
-       }
-
-       /* bail if no rom signature */
-       if (nv_rd08(bios, 0x700000) != 0x55 ||
-           nv_rd08(bios, 0x700001) != 0xaa)
-               goto out;
-
-       bios->size = nv_rd08(bios, 0x700002) * 512;
-       if (!bios->size)
-               goto out;
-
-       bios->data = kmalloc(bios->size, GFP_KERNEL);
-       if (bios->data) {
-               for (i = 0; i < bios->size; i++)
-                       nv_wo08(bios, i, nv_rd08(bios, 0x700000 + i));
-       }
-
-out:
-       if (device->card_type >= NV_50)
-               nv_wr32(bios, 0x001700, bar0);
-}
-
-static void
-nouveau_bios_shadow_prom(struct nouveau_bios *bios)
-{
-       struct nouveau_device *device = nv_device(bios);
-       u32 pcireg, access;
-       u16 pcir;
-       int i;
-
-       /* there is no prom on nv4x IGP's */
-       if (device->card_type == NV_40 && device->chipset >= 0x4c)
-               return;
-
-       /* enable access to rom */
-       if (device->card_type >= NV_50)
-               pcireg = 0x088050;
-       else
-               pcireg = 0x001850;
-       access = nv_mask(bios, pcireg, 0x00000001, 0x00000000);
-
-       /* WARNING: PROM accesses should always be 32-bits aligned. Other
-        * accesses work on most chipset but do not on Kepler chipsets
-        */
-
-       /* bail if no rom signature, with a workaround for a PROM reading
-        * issue on some chipsets.  the first read after a period of
-        * inactivity returns the wrong result, so retry the first header
-        * byte a few times before giving up as a workaround
-        */
-       i = 16;
-       do {
-               u32 data = le32_to_cpu(nv_rd32(bios, 0x300000)) & 0xffff;
-               if (data == 0xaa55)
-                       break;
-       } while (i--);
-
-       if (!i)
-               goto out;
-
-       /* read entire bios image to system memory */
-       bios->size = (le32_to_cpu(nv_rd32(bios, 0x300000)) >> 16) & 0xff;
-       bios->size = bios->size * 512;
-       if (!bios->size)
-               goto out;
-
-       bios->data = kmalloc(bios->size, GFP_KERNEL);
-       if (!bios->data)
-               goto out;
-
-       for (i = 0; i < bios->size; i += 4)
-               ((u32 *)bios->data)[i/4] = nv_rd32(bios, 0x300000 + i);
-
-       /* check the PCI record header */
-       pcir = nv_ro16(bios, 0x0018);
-       if (bios->data[pcir + 0] != 'P' ||
-           bios->data[pcir + 1] != 'C' ||
-           bios->data[pcir + 2] != 'I' ||
-           bios->data[pcir + 3] != 'R') {
-               bios->size = 0;
-               kfree(bios->data);
-       }
-
-out:
-       /* disable access to rom */
-       nv_wr32(bios, pcireg, access);
-}
-
-#if defined(CONFIG_ACPI) && defined(CONFIG_X86)
-int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
-bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
-#else
-static inline bool
-nouveau_acpi_rom_supported(struct pci_dev *pdev) {
-       return false;
-}
-
-static inline int
-nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) {
-       return -EINVAL;
-}
-#endif
-
-static void
-nouveau_bios_shadow_acpi(struct nouveau_bios *bios)
-{
-       struct pci_dev *pdev = nv_device(bios)->pdev;
-       int ret, cnt, i;
-
-       if (!nouveau_acpi_rom_supported(pdev)) {
-               bios->data = NULL;
-               return;
-       }
-
-       bios->size = 0;
-       bios->data = kmalloc(4096, GFP_KERNEL);
-       if (bios->data) {
-               if (nouveau_acpi_get_bios_chunk(bios->data, 0, 4096) == 4096)
-                       bios->size = bios->data[2] * 512;
-               kfree(bios->data);
+               memcpy(bios->data, prev, bios->size);
+               bios->size = length;
+               kfree(prev);
+               return 1;
        }
-
-       if (!bios->size)
-               return;
-
-       bios->data = kmalloc(bios->size, GFP_KERNEL);
-       if (bios->data) {
-               /* disobey the acpi spec - much faster on at least w530 ... */
-               ret = nouveau_acpi_get_bios_chunk(bios->data, 0, bios->size);
-               if (ret != bios->size ||
-                   nvbios_checksum(bios->data, bios->size)) {
-                       /* ... that didn't work, ok, i'll be good now */
-                       for (i = 0; i < bios->size; i += cnt) {
-                               cnt = min((bios->size - i), (u32)4096);
-                               ret = nouveau_acpi_get_bios_chunk(bios->data, i, cnt);
-                               if (ret != cnt)
-                                       break;
-                       }
-               }
-       }
-}
-
-static void
-nouveau_bios_shadow_pci(struct nouveau_bios *bios)
-{
-       struct pci_dev *pdev = nv_device(bios)->pdev;
-       size_t size;
-
-       if (!pci_enable_rom(pdev)) {
-               void __iomem *rom = pci_map_rom(pdev, &size);
-               if (rom && size) {
-                       bios->data = kmalloc(size, GFP_KERNEL);
-                       if (bios->data) {
-                               memcpy_fromio(bios->data, rom, size);
-                               bios->size = size;
-                       }
-               }
-               if (rom)
-                       pci_unmap_rom(pdev, rom);
-
-               pci_disable_rom(pdev);
-       }
-}
-
-static void
-nouveau_bios_shadow_platform(struct nouveau_bios *bios)
-{
-       struct pci_dev *pdev = nv_device(bios)->pdev;
-       size_t size;
-
-       void __iomem *rom = pci_platform_rom(pdev, &size);
-       if (rom && size) {
-               bios->data = kmalloc(size, GFP_KERNEL);
-               if (bios->data) {
-                       memcpy_fromio(bios->data, rom, size);
-                       bios->size = size;
-               }
-       }
-}
-
-static int
-nouveau_bios_score(struct nouveau_bios *bios, const bool writeable)
-{
-       if (bios->size < 3 || !bios->data || bios->data[0] != 0x55 ||
-                       bios->data[1] != 0xAA) {
-               nv_info(bios, "... signature not found\n");
-               return 0;
-       }
-
-       if (nvbios_checksum(bios->data,
-                       min_t(u32, bios->data[2] * 512, bios->size))) {
-               nv_info(bios, "... checksum invalid\n");
-               /* if a ro image is somewhat bad, it's probably all rubbish */
-               return writeable ? 2 : 1;
-       }
-
-       nv_info(bios, "... appears to be valid\n");
-       return 3;
-}
-
-struct methods {
-       const char desc[16];
-       void (*shadow)(struct nouveau_bios *);
-       const bool rw;
-       int score;
-       u32 size;
-       u8 *data;
-};
-
-static int
-nouveau_bios_shadow(struct nouveau_bios *bios)
-{
-       struct methods shadow_methods[] = {
-#if defined(__powerpc__)
-               { "OpenFirmware", nouveau_bios_shadow_of, true, 0, 0, NULL },
-#endif
-               { "PRAMIN", nouveau_bios_shadow_pramin, true, 0, 0, NULL },
-               { "PROM", nouveau_bios_shadow_prom, false, 0, 0, NULL },
-               { "ACPI", nouveau_bios_shadow_acpi, true, 0, 0, NULL },
-               { "PCIROM", nouveau_bios_shadow_pci, true, 0, 0, NULL },
-               { "PLATFORM", nouveau_bios_shadow_platform, true, 0, 0, NULL },
-               {}
-       };
-       struct methods *mthd, *best;
-       const struct firmware *fw;
-       const char *optarg;
-       int optlen, ret;
-       char *source;
-
-       optarg = nouveau_stropt(nv_device(bios)->cfgopt, "NvBios", &optlen);
-       source = optarg ? kstrndup(optarg, optlen, GFP_KERNEL) : NULL;
-       if (source) {
-               /* try to match one of the built-in methods */
-               mthd = shadow_methods;
-               do {
-                       if (strcasecmp(source, mthd->desc))
-                               continue;
-                       nv_info(bios, "source: %s\n", mthd->desc);
-
-                       mthd->shadow(bios);
-                       mthd->score = nouveau_bios_score(bios, mthd->rw);
-                       if (mthd->score) {
-                               kfree(source);
-                               return 0;
-                       }
-               } while ((++mthd)->shadow);
-
-               /* attempt to load firmware image */
-               ret = request_firmware(&fw, source, &nv_device(bios)->pdev->dev);
-               if (ret == 0) {
-                       bios->size = fw->size;
-                       bios->data = kmemdup(fw->data, fw->size, GFP_KERNEL);
-                       release_firmware(fw);
-
-                       nv_info(bios, "image: %s\n", source);
-                       if (nouveau_bios_score(bios, 1)) {
-                               kfree(source);
-                               return 0;
-                       }
-
-                       kfree(bios->data);
-                       bios->data = NULL;
-               }
-
-               nv_error(bios, "source \'%s\' invalid\n", source);
-               kfree(source);
-       }
-
-       mthd = shadow_methods;
-       do {
-               nv_info(bios, "checking %s for image...\n", mthd->desc);
-               mthd->shadow(bios);
-               mthd->score = nouveau_bios_score(bios, mthd->rw);
-               mthd->size = bios->size;
-               mthd->data = bios->data;
-               bios->data = NULL;
-       } while (mthd->score != 3 && (++mthd)->shadow);
-
-       mthd = shadow_methods;
-       best = mthd;
-       do {
-               if (mthd->score > best->score) {
-                       kfree(best->data);
-                       best = mthd;
-               }
-       } while ((++mthd)->shadow);
-
-       if (best->score) {
-               nv_info(bios, "using image from %s\n", best->desc);
-               bios->size = best->size;
-               bios->data = best->data;
-               return 0;
-       }
-
-       nv_error(bios, "unable to locate usable image\n");
-       return -EINVAL;
+       return 0;
 }
 
 static u8
@@ -472,7 +133,7 @@ nouveau_bios_ctor(struct nouveau_object *parent,
        if (ret)
                return ret;
 
-       ret = nouveau_bios_shadow(bios);
+       ret = nvbios_shadow(bios);
        if (ret)
                return ret;
 
index bd8d348385b38fe1a3231586bdea941be9657558..96099aff8b41a0067a4fb72731e530676f4b8852 100644 (file)
@@ -42,7 +42,7 @@ dcb_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
 
        *ver = nv_ro08(bios, dcb);
 
-       if (*ver >= 0x41) {
+       if (*ver >= 0x42) {
                nv_warn(bios, "DCB version 0x%02x unknown\n", *ver);
                return 0x0000;
        } else
@@ -157,17 +157,20 @@ dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len,
                                        break;
                                }
 
-                               switch (conf & 0x0f000000) {
-                               case 0x0f000000:
-                                       outp->dpconf.link_nr = 4;
-                                       break;
-                               case 0x03000000:
-                                       outp->dpconf.link_nr = 2;
-                                       break;
-                               case 0x01000000:
-                               default:
-                                       outp->dpconf.link_nr = 1;
-                                       break;
+                               outp->dpconf.link_nr = (conf & 0x0f000000) >> 24;
+                               if (*ver < 0x41) {
+                                       switch (outp->dpconf.link_nr) {
+                                       case 0x0f:
+                                               outp->dpconf.link_nr = 4;
+                                               break;
+                                       case 0x03:
+                                               outp->dpconf.link_nr = 2;
+                                               break;
+                                       case 0x01:
+                                       default:
+                                               outp->dpconf.link_nr = 1;
+                                               break;
+                                       }
                                }
 
                                /* fall-through... */
index 7f16e52d9bea2d45a6471e1e97300ae78a4b5cf7..51f3555996945b885d583dfcb34ff3dc0b305642 100644 (file)
@@ -40,6 +40,7 @@ nvbios_disp_table(struct nouveau_bios *bios,
                                switch (*ver) {
                                case 0x20:
                                case 0x21:
+                               case 0x22:
                                        *hdr = nv_ro08(bios, data + 0x01);
                                        *len = nv_ro08(bios, data + 0x02);
                                        *cnt = nv_ro08(bios, data + 0x03);
index f309dd657250f3031af58bcc8a8c56c2569eef13..cef53f81f12bfebcf62ecafda2b469c27592ce14 100644 (file)
@@ -41,6 +41,7 @@ nvbios_dp_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
                                case 0x21:
                                case 0x30:
                                case 0x40:
+                               case 0x41:
                                        *hdr = nv_ro08(bios, data + 0x01);
                                        *len = nv_ro08(bios, data + 0x02);
                                        *cnt = nv_ro08(bios, data + 0x03);
@@ -70,6 +71,7 @@ nvbios_dpout_entry(struct nouveau_bios *bios, u8 idx,
                        *cnt = nv_ro08(bios, outp + 0x04);
                        break;
                case 0x40:
+               case 0x41:
                        *hdr = nv_ro08(bios, data + 0x04);
                        *cnt = 0;
                        *len = 0;
@@ -108,6 +110,7 @@ nvbios_dpout_parse(struct nouveau_bios *bios, u8 idx,
                                info->script[4] = nv_ro16(bios, data + 0x10);
                        break;
                case 0x40:
+               case 0x41:
                        info->flags     = nv_ro08(bios, data + 0x04);
                        info->script[0] = nv_ro16(bios, data + 0x05);
                        info->script[1] = nv_ro16(bios, data + 0x07);
@@ -172,10 +175,11 @@ nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx,
                        break;
                case 0x30:
                case 0x40:
+               case 0x41:
                        info->pc    = nv_ro08(bios, data + 0x00);
                        info->dc    = nv_ro08(bios, data + 0x01);
                        info->pe    = nv_ro08(bios, data + 0x02);
-                       info->tx_pu = nv_ro08(bios, data + 0x03);
+                       info->tx_pu = nv_ro08(bios, data + 0x03) & 0x0f;
                        break;
                default:
                        data = 0x0000;
@@ -194,6 +198,10 @@ nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe,
        u16 data;
 
        if (*ver >= 0x30) {
+               /*XXX: there's a second set of these on at least 4.1, that
+                *     i've witnessed nvidia using instead of the first
+                *     on gm204.  figure out what/why
+                */
                const u8 vsoff[] = { 0, 4, 7, 9 };
                idx = (pc * 10) + vsoff[vs] + pe;
        } else {
index b2a676e53580ca6cd143e238b211cbcd7b5a027a..49285d4f7ca50a5c1ca224a48b8e27a8c431c2eb 100644 (file)
@@ -90,7 +90,7 @@ nvbios_extdev_find(struct nouveau_bios *bios, enum nvbios_extdev_type type,
        u16 entry;
 
        i = 0;
-       while (!(entry = nvbios_extdev_entry(bios, i++, &ver, &len))) {
+       while ((entry = nvbios_extdev_entry(bios, i++, &ver, &len))) {
                extdev_parse_entry(bios, entry, func);
                if (func->type == type)
                        return 0;
index cfb9288c6d28cbd2f2ea662bf77176c386ad14d9..282320ba9264155914600c397e34bbef6682db4b 100644 (file)
@@ -39,6 +39,11 @@ dcb_i2c_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
                        i2c = nv_ro16(bios, dcb + 4);
        }
 
+       if (i2c && *ver >= 0x42) {
+               nv_warn(bios, "ccb %02x not supported\n", *ver);
+               return 0x0000;
+       }
+
        if (i2c && *ver >= 0x30) {
                *ver = nv_ro08(bios, i2c + 0);
                *hdr = nv_ro08(bios, i2c + 1);
@@ -70,14 +75,25 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info)
        u8  ver, len;
        u16 ent = dcb_i2c_entry(bios, idx, &ver, &len);
        if (ent) {
-               info->type  = nv_ro08(bios, ent + 3);
-               info->share = DCB_I2C_UNUSED;
-               if (ver < 0x30) {
-                       info->type &= 0x07;
+               if (ver >= 0x41) {
+                       if (!(nv_ro32(bios, ent) & 0x80000000))
+                               info->type = DCB_I2C_UNUSED;
+                       else
+                               info->type = DCB_I2C_PMGR;
+               } else
+               if (ver >= 0x30) {
+                       info->type = nv_ro08(bios, ent + 0x03);
+               } else {
+                       info->type = nv_ro08(bios, ent + 0x03) & 0x07;
                        if (info->type == 0x07)
                                info->type = DCB_I2C_UNUSED;
                }
 
+               info->drive = DCB_I2C_UNUSED;
+               info->sense = DCB_I2C_UNUSED;
+               info->share = DCB_I2C_UNUSED;
+               info->auxch = DCB_I2C_UNUSED;
+
                switch (info->type) {
                case DCB_I2C_NV04_BIT:
                        info->drive = nv_ro08(bios, ent + 0);
@@ -87,12 +103,23 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info)
                        info->drive = nv_ro08(bios, ent + 1);
                        return 0;
                case DCB_I2C_NVIO_BIT:
-               case DCB_I2C_NVIO_AUX:
                        info->drive = nv_ro08(bios, ent + 0) & 0x0f;
-                       if (nv_ro08(bios, ent + 1) & 0x01) {
-                               info->share  = nv_ro08(bios, ent + 1) >> 1;
-                               info->share &= 0x0f;
-                       }
+                       if (nv_ro08(bios, ent + 1) & 0x01)
+                               info->share = nv_ro08(bios, ent + 1) >> 1;
+                       return 0;
+               case DCB_I2C_NVIO_AUX:
+                       info->auxch = nv_ro08(bios, ent + 0) & 0x0f;
+                       if (nv_ro08(bios, ent + 1) & 0x01)
+                                       info->share = info->auxch;
+                       return 0;
+               case DCB_I2C_PMGR:
+                       info->drive = (nv_ro16(bios, ent + 0) & 0x01f) >> 0;
+                       if (info->drive == 0x1f)
+                               info->drive = DCB_I2C_UNUSED;
+                       info->auxch = (nv_ro16(bios, ent + 0) & 0x3e0) >> 5;
+                       if (info->auxch == 0x1f)
+                               info->auxch = DCB_I2C_UNUSED;
+                       info->share = info->auxch;
                        return 0;
                case DCB_I2C_UNUSED:
                        return 0;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/image.c b/drivers/gpu/drm/nouveau/core/subdev/bios/image.c
new file mode 100644 (file)
index 0000000..373f9a5
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/image.h>
+#include <subdev/bios/pcir.h>
+#include <subdev/bios/npde.h>
+
+static bool
+nvbios_imagen(struct nouveau_bios *bios, struct nvbios_image *image)
+{
+       struct nvbios_pcirT pcir;
+       struct nvbios_npdeT npde;
+       u8  ver;
+       u16 hdr;
+       u32 data;
+
+       switch ((data = nv_ro16(bios, image->base + 0x00))) {
+       case 0xaa55:
+       case 0xbb77:
+       case 0x4e56: /* NV */
+               break;
+       default:
+               nv_debug(bios, "%08x: ROM signature (%04x) unknown\n",
+                        image->base, data);
+               return false;
+       }
+
+       if (!(data = nvbios_pcirTp(bios, image->base, &ver, &hdr, &pcir)))
+               return false;
+       image->size = pcir.image_size;
+       image->type = pcir.image_type;
+       image->last = pcir.last;
+
+       if (image->type != 0x70) {
+               if (!(data = nvbios_npdeTp(bios, image->base, &npde)))
+                       return true;
+               image->size = npde.image_size;
+               image->last = npde.last;
+       } else {
+               image->last = true;
+       }
+
+       return true;
+}
+
+bool
+nvbios_image(struct nouveau_bios *bios, int idx, struct nvbios_image *image)
+{
+       memset(image, 0x00, sizeof(*image));
+       do {
+               image->base += image->size;
+               if (image->last || !nvbios_imagen(bios, image))
+                       return false;
+       } while(idx--);
+       return true;
+}
index 626380f9e4c0192e877bef46b4a154b68c972b39..c6579ef32cd11380da2a4e2fb63117d652f6ade2 100644 (file)
@@ -255,6 +255,8 @@ init_i2c(struct nvbios_init *init, int index)
                }
 
                index = init->outp->i2c_index;
+               if (init->outp->type == DCB_OUTPUT_DP)
+                       index += NV_I2C_AUX(0);
        }
 
        return i2c->find(i2c, index);
@@ -278,7 +280,7 @@ init_wri2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg, u8 val)
        return -ENODEV;
 }
 
-static int
+static u8
 init_rdauxr(struct nvbios_init *init, u32 addr)
 {
        struct nouveau_i2c_port *port = init_i2c(init, -2);
@@ -286,20 +288,24 @@ init_rdauxr(struct nvbios_init *init, u32 addr)
 
        if (port && init_exec(init)) {
                int ret = nv_rdaux(port, addr, &data, 1);
-               if (ret)
-                       return ret;
-               return data;
+               if (ret == 0)
+                       return data;
+               trace("auxch read failed with %d\n", ret);
        }
 
-       return -ENODEV;
+       return 0x00;
 }
 
 static int
 init_wrauxr(struct nvbios_init *init, u32 addr, u8 data)
 {
        struct nouveau_i2c_port *port = init_i2c(init, -2);
-       if (port && init_exec(init))
-               return nv_wraux(port, addr, &data, 1);
+       if (port && init_exec(init)) {
+               int ret = nv_wraux(port, addr, &data, 1);
+               if (ret)
+                       trace("auxch write failed with %d\n", ret);
+               return ret;
+       }
        return -ENODEV;
 }
 
@@ -837,6 +843,40 @@ init_io_or(struct nvbios_init *init)
        init_wrvgai(init, 0x03d4, index, data | (1 << or));
 }
 
+/**
+ * INIT_ANDN_REG - opcode 0x47
+ *
+ */
+static void
+init_andn_reg(struct nvbios_init *init)
+{
+       struct nouveau_bios *bios = init->bios;
+       u32  reg = nv_ro32(bios, init->offset + 1);
+       u32 mask = nv_ro32(bios, init->offset + 5);
+
+       trace("ANDN_REG\tR[0x%06x] &= ~0x%08x\n", reg, mask);
+       init->offset += 9;
+
+       init_mask(init, reg, mask, 0);
+}
+
+/**
+ * INIT_OR_REG - opcode 0x48
+ *
+ */
+static void
+init_or_reg(struct nvbios_init *init)
+{
+       struct nouveau_bios *bios = init->bios;
+       u32  reg = nv_ro32(bios, init->offset + 1);
+       u32 mask = nv_ro32(bios, init->offset + 5);
+
+       trace("OR_REG\tR[0x%06x] |= 0x%08x\n", reg, mask);
+       init->offset += 9;
+
+       init_mask(init, reg, 0, mask);
+}
+
 /**
  * INIT_INDEX_ADDRESS_LATCHED - opcode 0x49
  *
@@ -2068,6 +2108,8 @@ static struct nvbios_init_opcode {
        [0x3a] = { init_dp_condition },
        [0x3b] = { init_io_mask_or },
        [0x3c] = { init_io_or },
+       [0x47] = { init_andn_reg },
+       [0x48] = { init_or_reg },
        [0x49] = { init_idx_addr_latched },
        [0x4a] = { init_io_restrict_pll2 },
        [0x4b] = { init_pll2 },
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/npde.c b/drivers/gpu/drm/nouveau/core/subdev/bios/npde.c
new file mode 100644 (file)
index 0000000..d694716
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/npde.h>
+#include <subdev/bios/pcir.h>
+
+u32
+nvbios_npdeTe(struct nouveau_bios *bios, u32 base)
+{
+       struct nvbios_pcirT pcir;
+       u8  ver; u16 hdr;
+       u32 data = nvbios_pcirTp(bios, base, &ver, &hdr, &pcir);
+       if (data = (data + hdr + 0x0f) & ~0x0f, data) {
+               switch (nv_ro32(bios, data + 0x00)) {
+               case 0x4544504e: /* NPDE */
+                       break;
+               default:
+                       nv_debug(bios, "%08x: NPDE signature (%08x) unknown\n",
+                                data, nv_ro32(bios, data + 0x00));
+                       data = 0;
+                       break;
+               }
+       }
+       return data;
+}
+
+u32
+nvbios_npdeTp(struct nouveau_bios *bios, u32 base, struct nvbios_npdeT *info)
+{
+       u32 data = nvbios_npdeTe(bios, base);
+       memset(info, 0x00, sizeof(*info));
+       if (data) {
+               info->image_size = nv_ro16(bios, data + 0x08) * 512;
+               info->last = nv_ro08(bios, data + 0x0a) & 0x80;
+       }
+       return data;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/pcir.c b/drivers/gpu/drm/nouveau/core/subdev/bios/pcir.c
new file mode 100644 (file)
index 0000000..91dae26
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/pcir.h>
+
+u32
+nvbios_pcirTe(struct nouveau_bios *bios, u32 base, u8 *ver, u16 *hdr)
+{
+       u32 data = nv_ro16(bios, base + 0x18);
+       if (data) {
+               data += base;
+               switch (nv_ro32(bios, data + 0x00)) {
+               case 0x52494350: /* PCIR */
+               case 0x53494752: /* RGIS */
+               case 0x5344504e: /* NPDS */
+                       *hdr = nv_ro16(bios, data + 0x0a);
+                       *ver = nv_ro08(bios, data + 0x0c);
+                       break;
+               default:
+                       nv_debug(bios, "%08x: PCIR signature (%08x) unknown\n",
+                                data, nv_ro32(bios, data + 0x00));
+                       data = 0;
+                       break;
+               }
+       }
+       return data;
+}
+
+u32
+nvbios_pcirTp(struct nouveau_bios *bios, u32 base, u8 *ver, u16 *hdr,
+             struct nvbios_pcirT *info)
+{
+       u32 data = nvbios_pcirTe(bios, base, ver, hdr);
+       memset(info, 0x00, sizeof(*info));
+       if (data) {
+               info->vendor_id = nv_ro16(bios, data + 0x04);
+               info->device_id = nv_ro16(bios, data + 0x06);
+               info->class_code[0] = nv_ro08(bios, data + 0x0d);
+               info->class_code[1] = nv_ro08(bios, data + 0x0e);
+               info->class_code[2] = nv_ro08(bios, data + 0x0f);
+               info->image_size = nv_ro16(bios, data + 0x10) * 512;
+               info->image_rev = nv_ro16(bios, data + 0x12);
+               info->image_type = nv_ro08(bios, data + 0x14);
+               info->last = nv_ro08(bios, data + 0x15) & 0x80;
+       }
+       return data;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/pmu.c b/drivers/gpu/drm/nouveau/core/subdev/bios/pmu.c
new file mode 100644 (file)
index 0000000..66c56ba
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/image.h>
+#include <subdev/bios/pmu.h>
+
+static u32
+weirdo_pointer(struct nouveau_bios *bios, u32 data)
+{
+       struct nvbios_image image;
+       int idx = 0;
+       if (nvbios_image(bios, idx++, &image)) {
+               data -= image.size;
+               while (nvbios_image(bios, idx++, &image)) {
+                       if (image.type == 0xe0)
+                               return image.base + data;
+               }
+       }
+       return 0;
+}
+
+u32
+nvbios_pmuTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+       struct bit_entry bit_p;
+       u32 data = 0;
+
+       if (!bit_entry(bios, 'p', &bit_p)) {
+               if (bit_p.version == 2 && bit_p.length >= 4)
+                       data = nv_ro32(bios, bit_p.offset + 0x00);
+               if ((data = weirdo_pointer(bios, data))) {
+                       *ver = nv_ro08(bios, data + 0x00); /* maybe? */
+                       *hdr = nv_ro08(bios, data + 0x01);
+                       *len = nv_ro08(bios, data + 0x02);
+                       *cnt = nv_ro08(bios, data + 0x03);
+               }
+       }
+
+       return data;
+}
+
+u32
+nvbios_pmuTp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+            struct nvbios_pmuT *info)
+{
+       u32 data = nvbios_pmuTe(bios, ver, hdr, cnt, len);
+       memset(info, 0x00, sizeof(*info));
+       switch (!!data * *ver) {
+       default:
+               break;
+       }
+       return data;
+}
+
+u32
+nvbios_pmuEe(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr)
+{
+       u8  cnt, len;
+       u32 data = nvbios_pmuTe(bios, ver, hdr, &cnt, &len);
+       if (data && idx < cnt) {
+               data = data + *hdr + (idx * len);
+               *hdr = len;
+               return data;
+       }
+       return 0;
+}
+
+u32
+nvbios_pmuEp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
+            struct nvbios_pmuE *info)
+{
+       u32 data = nvbios_pmuEe(bios, idx, ver, hdr);
+       memset(info, 0x00, sizeof(*info));
+       switch (!!data * *ver) {
+       default:
+               info->type = nv_ro08(bios, data + 0x00);
+               info->data = nv_ro32(bios, data + 0x02);
+               break;
+       }
+       return data;
+}
+
+bool
+nvbios_pmuRm(struct nouveau_bios *bios, u8 type, struct nvbios_pmuR *info)
+{
+       struct nvbios_pmuE pmuE;
+       u8  ver, hdr, idx = 0;
+       u32 data;
+       memset(info, 0x00, sizeof(*info));
+       while ((data = nvbios_pmuEp(bios, idx++, &ver, &hdr, &pmuE))) {
+               if ( pmuE.type == type &&
+                   (data = weirdo_pointer(bios, pmuE.data))) {
+                       info->init_addr_pmu = nv_ro32(bios, data + 0x08);
+                       info->args_addr_pmu = nv_ro32(bios, data + 0x0c);
+                       info->boot_addr     = data + 0x30;
+                       info->boot_addr_pmu = nv_ro32(bios, data + 0x10) +
+                                             nv_ro32(bios, data + 0x18);
+                       info->boot_size     = nv_ro32(bios, data + 0x1c) -
+                                             nv_ro32(bios, data + 0x18);
+                       info->code_addr     = info->boot_addr + info->boot_size;
+                       info->code_addr_pmu = info->boot_addr_pmu +
+                                             info->boot_size;
+                       info->code_size     = nv_ro32(bios, data + 0x20);
+                       info->data_addr     = data + 0x30 +
+                                             nv_ro32(bios, data + 0x24);
+                       info->data_addr_pmu = nv_ro32(bios, data + 0x28);
+                       info->data_size     = nv_ro32(bios, data + 0x2c);
+                       return true;
+               }
+       }
+       return false;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/priv.h b/drivers/gpu/drm/nouveau/core/subdev/bios/priv.h
new file mode 100644 (file)
index 0000000..187d225
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __NVKM_BIOS_PRIV_H__
+#define __NVKM_BIOS_PRIV_H__
+
+#include <subdev/bios.h>
+
+struct nvbios_source {
+       const char *name;
+       void *(*init)(struct nouveau_bios *, const char *);
+       void  (*fini)(void *);
+       u32   (*read)(void *, u32 offset, u32 length, struct nouveau_bios *);
+       bool rw;
+};
+
+int nvbios_extend(struct nouveau_bios *, u32 length);
+int nvbios_shadow(struct nouveau_bios *);
+
+extern const struct nvbios_source nvbios_rom;
+extern const struct nvbios_source nvbios_ramin;
+extern const struct nvbios_source nvbios_acpi_fast;
+extern const struct nvbios_source nvbios_acpi_slow;
+extern const struct nvbios_source nvbios_pcirom;
+extern const struct nvbios_source nvbios_platform;
+extern const struct nvbios_source nvbios_of;
+
+#endif
index 6c401f70ab99ae380b6c614983a997a9244a97d9..1623c8dfe797362042efddb17bb1e827e13cd6b7 100644 (file)
@@ -25,6 +25,7 @@
 #include <subdev/bios.h>
 #include <subdev/bios/bit.h>
 #include <subdev/bios/ramcfg.h>
+#include <subdev/bios/M0203.h>
 
 static u8
 nvbios_ramcfg_strap(struct nouveau_subdev *subdev)
@@ -54,12 +55,22 @@ nvbios_ramcfg_index(struct nouveau_subdev *subdev)
        u8 strap = nvbios_ramcfg_strap(subdev);
        u32 xlat = 0x00000000;
        struct bit_entry bit_M;
+       struct nvbios_M0203E M0203E;
+       u8 ver, hdr;
 
        if (!bit_entry(bios, 'M', &bit_M)) {
                if (bit_M.version == 1 && bit_M.length >= 5)
                        xlat = nv_ro16(bios, bit_M.offset + 3);
-               if (bit_M.version == 2 && bit_M.length >= 3)
+               if (bit_M.version == 2 && bit_M.length >= 3) {
+                       /*XXX: is M ever shorter than this?
+                        *     if not - what is xlat used for now?
+                        *     also - sigh..
+                        */
+                       if (bit_M.length >= 7 &&
+                           nvbios_M0203Em(bios, strap, &ver, &hdr, &M0203E))
+                               return M0203E.group;
                        xlat = nv_ro16(bios, bit_M.offset + 1);
+               }
        }
 
        if (xlat)
index 585e69331ccce91ac3bc694e7fc09942a06ba993..c5685228c3228c6c23c8d707ade0fb4e024cddf8 100644 (file)
@@ -162,8 +162,9 @@ nvbios_rammapSp(struct nouveau_bios *bios, u32 data,
                p->ramcfg_10_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3;
                p->ramcfg_10_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4;
                p->ramcfg_10_02_20 = (nv_ro08(bios, data + 0x02) & 0x20) >> 5;
-               p->ramcfg_10_02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
+               p->ramcfg_10_DLLoff = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
                p->ramcfg_10_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0;
+               p->ramcfg_10_04_01 = (nv_ro08(bios, data + 0x04) & 0x01) >> 0;
                p->ramcfg_10_05    = (nv_ro08(bios, data + 0x05) & 0xff) >> 0;
                p->ramcfg_10_06    = (nv_ro08(bios, data + 0x06) & 0xff) >> 0;
                p->ramcfg_10_07    = (nv_ro08(bios, data + 0x07) & 0xff) >> 0;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadow.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadow.c
new file mode 100644 (file)
index 0000000..bb9e001
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "priv.h"
+#include <core/option.h>
+#include <subdev/bios/image.h>
+
+struct shadow {
+       struct nouveau_oclass base;
+       u32 skip;
+       const struct nvbios_source *func;
+       void *data;
+       u32 size;
+       int score;
+};
+
+static bool
+shadow_fetch(struct nouveau_bios *bios, u32 upto)
+{
+       struct shadow *mthd = (void *)nv_object(bios)->oclass;
+       const u32 limit = (upto + 3) & ~3;
+       const u32 start = bios->size;
+       void *data = mthd->data;
+       if (nvbios_extend(bios, limit) > 0) {
+               u32 read = mthd->func->read(data, start, limit - start, bios);
+               bios->size = start + read;
+       }
+       return bios->size >= limit;
+}
+
+static u8
+shadow_rd08(struct nouveau_object *object, u64 addr)
+{
+       struct nouveau_bios *bios = (void *)object;
+       if (shadow_fetch(bios, addr + 1))
+               return bios->data[addr];
+       return 0x00;
+}
+
+static u16
+shadow_rd16(struct nouveau_object *object, u64 addr)
+{
+       struct nouveau_bios *bios = (void *)object;
+       if (shadow_fetch(bios, addr + 2))
+               return get_unaligned_le16(&bios->data[addr]);
+       return 0x0000;
+}
+
+static u32
+shadow_rd32(struct nouveau_object *object, u64 addr)
+{
+       struct nouveau_bios *bios = (void *)object;
+       if (shadow_fetch(bios, addr + 4))
+               return get_unaligned_le32(&bios->data[addr]);
+       return 0x00000000;
+}
+
+static struct nouveau_oclass
+shadow_class = {
+       .handle = NV_SUBDEV(VBIOS, 0x00),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .rd08 = shadow_rd08,
+               .rd16 = shadow_rd16,
+               .rd32 = shadow_rd32,
+       },
+};
+
+static int
+shadow_image(struct nouveau_bios *bios, int idx, struct shadow *mthd)
+{
+       struct nvbios_image image;
+       int score = 1;
+
+       if (!nvbios_image(bios, idx, &image)) {
+               nv_debug(bios, "image %d invalid\n", idx);
+               return 0;
+       }
+       nv_debug(bios, "%08x: type %02x, %d bytes\n",
+                image.base, image.type, image.size);
+
+       if (!shadow_fetch(bios, image.size)) {
+               nv_debug(bios, "%08x: fetch failed\n", image.base);
+               return 0;
+       }
+
+       switch (image.type) {
+       case 0x00:
+               if (nvbios_checksum(&bios->data[image.base], image.size)) {
+                       nv_debug(bios, "%08x: checksum failed\n", image.base);
+                       if (mthd->func->rw)
+                               score += 1;
+                       score += 1;
+               } else {
+                       score += 3;
+               }
+               break;
+       default:
+               score += 3;
+               break;
+       }
+
+       if (!image.last)
+               score += shadow_image(bios, idx + 1, mthd);
+       return score;
+}
+
+static int
+shadow_score(struct nouveau_bios *bios, struct shadow *mthd)
+{
+       struct nouveau_oclass *oclass = nv_object(bios)->oclass;
+       int score;
+       nv_object(bios)->oclass = &mthd->base;
+       score = shadow_image(bios, 0, mthd);
+       nv_object(bios)->oclass = oclass;
+       return score;
+
+}
+
+static int
+shadow_method(struct nouveau_bios *bios, struct shadow *mthd, const char *name)
+{
+       const struct nvbios_source *func = mthd->func;
+       if (func->name) {
+               nv_debug(bios, "trying %s...\n", name ? name : func->name);
+               if (func->init) {
+                       mthd->data = func->init(bios, name);
+                       if (IS_ERR(mthd->data)) {
+                               mthd->data = NULL;
+                               return 0;
+                       }
+               }
+               mthd->score = shadow_score(bios, mthd);
+               if (func->fini)
+                       func->fini(mthd->data);
+               nv_debug(bios, "scored %d\n", mthd->score);
+               mthd->data = bios->data;
+               mthd->size = bios->size;
+               bios->data  = NULL;
+               bios->size  = 0;
+       }
+       return mthd->score;
+}
+
+static u32
+shadow_fw_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
+{
+       const struct firmware *fw = data;
+       if (offset + length <= fw->size) {
+               memcpy(bios->data + offset, fw->data + offset, length);
+               return length;
+       }
+       return 0;
+}
+
+static void *
+shadow_fw_init(struct nouveau_bios *bios, const char *name)
+{
+       struct device *dev = &nv_device(bios)->pdev->dev;
+       const struct firmware *fw;
+       int ret = request_firmware(&fw, name, dev);
+       if (ret)
+               return ERR_PTR(-ENOENT);
+       return (void *)fw;
+}
+
+static const struct nvbios_source
+shadow_fw = {
+       .name = "firmware",
+       .init = shadow_fw_init,
+       .fini = (void(*)(void *))release_firmware,
+       .read = shadow_fw_read,
+       .rw = false,
+};
+
+int
+nvbios_shadow(struct nouveau_bios *bios)
+{
+       struct shadow mthds[] = {
+               { shadow_class, 0, &nvbios_of },
+               { shadow_class, 0, &nvbios_ramin },
+               { shadow_class, 0, &nvbios_rom },
+               { shadow_class, 0, &nvbios_acpi_fast },
+               { shadow_class, 4, &nvbios_acpi_slow },
+               { shadow_class, 1, &nvbios_pcirom },
+               { shadow_class, 1, &nvbios_platform },
+               { shadow_class }
+       }, *mthd = mthds, *best = NULL;
+       const char *optarg;
+       char *source;
+       int optlen;
+
+       /* handle user-specified bios source */
+       optarg = nouveau_stropt(nv_device(bios)->cfgopt, "NvBios", &optlen);
+       source = optarg ? kstrndup(optarg, optlen, GFP_KERNEL) : NULL;
+       if (source) {
+               /* try to match one of the built-in methods */
+               for (mthd = mthds; mthd->func; mthd++) {
+                       if (mthd->func->name &&
+                           !strcasecmp(source, mthd->func->name)) {
+                               best = mthd;
+                               if (shadow_method(bios, mthd, NULL))
+                                       break;
+                       }
+               }
+
+               /* otherwise, attempt to load as firmware */
+               if (!best && (best = mthd)) {
+                       mthd->func = &shadow_fw;
+                       shadow_method(bios, mthd, source);
+                       mthd->func = NULL;
+               }
+
+               if (!best->score) {
+                       nv_error(bios, "%s invalid\n", source);
+                       kfree(source);
+                       source = NULL;
+               }
+       }
+
+       /* scan all potential bios sources, looking for best image */
+       if (!best || !best->score) {
+               for (mthd = mthds, best = mthd; mthd->func; mthd++) {
+                       if (!mthd->skip || best->score < mthd->skip) {
+                               if (shadow_method(bios, mthd, NULL)) {
+                                       if (mthd->score > best->score)
+                                               best = mthd;
+                               }
+                       }
+               }
+       }
+
+       /* cleanup the ones we didn't use */
+       for (mthd = mthds; mthd->func; mthd++) {
+               if (mthd != best)
+                       kfree(mthd->data);
+       }
+
+       if (!best->score) {
+               nv_fatal(bios, "unable to locate usable image\n");
+               return -EINVAL;
+       }
+
+       nv_info(bios, "using image from %s\n", best->func ?
+               best->func->name : source);
+       bios->data = best->data;
+       bios->size = best->size;
+       kfree(source);
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowacpi.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadowacpi.c
new file mode 100644 (file)
index 0000000..bc130c1
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "priv.h"
+
+#if defined(CONFIG_ACPI) && defined(CONFIG_X86)
+int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
+bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
+#else
+static inline bool
+nouveau_acpi_rom_supported(struct pci_dev *pdev)
+{
+       return false;
+}
+
+static inline int
+nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len)
+{
+       return -EINVAL;
+}
+#endif
+
+/* This version of the shadow function disobeys the ACPI spec and tries
+ * to fetch in units of more than 4KiB at a time.  This is a LOT faster
+ * on some systems, such as Lenovo W530.
+ */
+static u32
+acpi_read_fast(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
+{
+       u32 limit = (offset + length + 0xfff) & ~0xfff;
+       u32 start = offset & ~0x00000fff;
+       u32 fetch = limit - start;
+
+       if (nvbios_extend(bios, limit) > 0) {
+               int ret = nouveau_acpi_get_bios_chunk(bios->data, start, fetch);
+               if (ret == fetch)
+                       return fetch;
+       }
+
+       return 0;
+}
+
+/* Other systems, such as the one in fdo#55948, will report a success
+ * but only return 4KiB of data.  The common bios fetching logic will
+ * detect an invalid image, and fall back to this version of the read
+ * function.
+ */
+static u32
+acpi_read_slow(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
+{
+       u32 limit = (offset + length + 0xfff) & ~0xfff;
+       u32 start = offset & ~0xfff;
+       u32 fetch = 0;
+
+       if (nvbios_extend(bios, limit) > 0) {
+               while (start + fetch < limit) {
+                       int ret = nouveau_acpi_get_bios_chunk(bios->data,
+                                                             start + fetch,
+                                                             0x1000);
+                       if (ret != 0x1000)
+                               break;
+                       fetch += 0x1000;
+               }
+       }
+
+       return fetch;
+}
+
+static void *
+acpi_init(struct nouveau_bios *bios, const char *name)
+{
+       if (!nouveau_acpi_rom_supported(nv_device(bios)->pdev))
+               return ERR_PTR(-ENODEV);
+       return NULL;
+}
+
+const struct nvbios_source
+nvbios_acpi_fast = {
+       .name = "ACPI",
+       .init = acpi_init,
+       .read = acpi_read_fast,
+       .rw = false,
+};
+
+const struct nvbios_source
+nvbios_acpi_slow = {
+       .name = "ACPI",
+       .init = acpi_init,
+       .read = acpi_read_slow,
+       .rw = false,
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowof.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadowof.c
new file mode 100644 (file)
index 0000000..3abe487
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "priv.h"
+
+#if defined(__powerpc__)
+struct priv {
+       const void __iomem *data;
+       int size;
+};
+
+static u32
+of_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
+{
+       struct priv *priv = data;
+       if (offset + length <= priv->size) {
+               memcpy_fromio(bios->data + offset, priv->data + offset, length);
+               return length;
+       }
+       return 0;
+}
+
+static void *
+of_init(struct nouveau_bios *bios, const char *name)
+{
+       struct pci_dev *pdev = nv_device(bios)->pdev;
+       struct device_node *dn;
+       struct priv *priv;
+       if (!(dn = pci_device_to_OF_node(pdev)))
+               return ERR_PTR(-ENODEV);
+       if (!(priv = kzalloc(sizeof(*priv), GFP_KERNEL)))
+               return ERR_PTR(-ENOMEM);
+       if ((priv->data = of_get_property(dn, "NVDA,BMP", &priv->size)))
+               return priv;
+       kfree(priv);
+       return ERR_PTR(-EINVAL);
+}
+
+const struct nvbios_source
+nvbios_of = {
+       .name = "OpenFirmware",
+       .init = of_init,
+       .fini = (void(*)(void *))kfree,
+       .read = of_read,
+       .rw = false,
+};
+#else
+const struct nvbios_source
+nvbios_of = {
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowpci.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadowpci.c
new file mode 100644 (file)
index 0000000..1d0389c
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "priv.h"
+
+struct priv {
+       struct pci_dev *pdev;
+       void __iomem *rom;
+       size_t size;
+};
+
+static u32
+pcirom_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
+{
+       struct priv *priv = data;
+       if (offset + length <= priv->size) {
+               memcpy_fromio(bios->data + offset, priv->rom + offset, length);
+               return length;
+       }
+       return 0;
+}
+
+static void
+pcirom_fini(void *data)
+{
+       struct priv *priv = data;
+       pci_unmap_rom(priv->pdev, priv->rom);
+       pci_disable_rom(priv->pdev);
+       kfree(priv);
+}
+
+static void *
+pcirom_init(struct nouveau_bios *bios, const char *name)
+{
+       struct pci_dev *pdev = nv_device(bios)->pdev;
+       struct priv *priv = NULL;
+       int ret;
+
+       if (!(ret = pci_enable_rom(pdev))) {
+               if (ret = -ENOMEM,
+                   (priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
+                       if (ret = -EFAULT,
+                           (priv->rom = pci_map_rom(pdev, &priv->size))) {
+                               priv->pdev = pdev;
+                               return priv;
+                       }
+                       kfree(priv);
+               }
+               pci_disable_rom(pdev);
+       }
+
+       return ERR_PTR(ret);
+}
+
+const struct nvbios_source
+nvbios_pcirom = {
+       .name = "PCIROM",
+       .init = pcirom_init,
+       .fini = pcirom_fini,
+       .read = pcirom_read,
+       .rw = true,
+};
+
+static void *
+platform_init(struct nouveau_bios *bios, const char *name)
+{
+       struct pci_dev *pdev = nv_device(bios)->pdev;
+       struct priv *priv;
+       int ret = -ENOMEM;
+
+       if ((priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
+               if (ret = -ENODEV,
+                   (priv->rom = pci_platform_rom(pdev, &priv->size)))
+                       return priv;
+               kfree(priv);
+       }
+
+       return ERR_PTR(ret);
+}
+
+const struct nvbios_source
+nvbios_platform = {
+       .name = "PLATFORM",
+       .init = platform_init,
+       .fini = (void(*)(void *))kfree,
+       .read = pcirom_read,
+       .rw = true,
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowramin.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadowramin.c
new file mode 100644 (file)
index 0000000..5e58bba
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "priv.h"
+
+struct priv {
+       struct nouveau_bios *bios;
+       u32 bar0;
+};
+
+static u32
+pramin_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
+{
+       u32 i;
+       if (offset + length <= 0x00100000) {
+               for (i = offset; i < offset + length; i += 4)
+                       *(u32 *)&bios->data[i] = nv_rd32(bios, 0x700000 + i);
+               return length;
+       }
+       return 0;
+}
+
+static void
+pramin_fini(void *data)
+{
+       struct priv *priv = data;
+       nv_wr32(priv->bios, 0x001700, priv->bar0);
+       kfree(priv);
+}
+
+static void *
+pramin_init(struct nouveau_bios *bios, const char *name)
+{
+       struct priv *priv = NULL;
+       u64 addr = 0;
+
+       /* PRAMIN always potentially available prior to nv50 */
+       if (nv_device(bios)->card_type < NV_50)
+               return NULL;
+
+       /* we can't get the bios image pointer without PDISP */
+       if (nv_device(bios)->card_type >= GM100)
+               addr = nv_rd32(bios, 0x021c04);
+       else
+       if (nv_device(bios)->card_type >= NV_C0)
+               addr = nv_rd32(bios, 0x022500);
+       if (addr & 0x00000001) {
+               nv_debug(bios, "... display disabled\n");
+               return ERR_PTR(-ENODEV);
+       }
+
+       /* check that the window is enabled and in vram, particularly
+        * important as we don't want to be touching vram on an
+        * uninitialised board
+        */
+       addr = nv_rd32(bios, 0x619f04);
+       if (!(addr & 0x00000008)) {
+               nv_debug(bios, "... not enabled\n");
+               return ERR_PTR(-ENODEV);
+       }
+       if ( (addr & 0x00000003) != 1) {
+               nv_debug(bios, "... not in vram\n");
+               return ERR_PTR(-ENODEV);
+       }
+
+       /* some alternate method inherited from xf86-video-nv... */
+       addr = (addr & 0xffffff00) << 8;
+       if (!addr) {
+               addr  = (u64)nv_rd32(bios, 0x001700) << 16;
+               addr += 0xf0000;
+       }
+
+       /* modify bar0 PRAMIN window to cover the bios image */
+       if (!(priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
+               nv_error(bios, "... out of memory\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       priv->bios = bios;
+       priv->bar0 = nv_rd32(bios, 0x001700);
+       nv_wr32(bios, 0x001700, addr >> 16);
+       return priv;
+}
+
+const struct nvbios_source
+nvbios_ramin = {
+       .name = "PRAMIN",
+       .init = pramin_init,
+       .fini = pramin_fini,
+       .read = pramin_read,
+       .rw = true,
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowrom.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadowrom.c
new file mode 100644 (file)
index 0000000..b7992bc
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "priv.h"
+
+static u32
+prom_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
+{
+       u32 i;
+       if (offset + length <= 0x00100000) {
+               for (i = offset; i < offset + length; i += 4)
+                       *(u32 *)&bios->data[i] = nv_rd32(bios, 0x300000 + i);
+               return length;
+       }
+       return 0;
+}
+
+static void
+prom_fini(void *data)
+{
+       struct nouveau_bios *bios = data;
+       if (nv_device(bios)->card_type < NV_50)
+               nv_mask(bios, 0x001850, 0x00000001, 0x00000001);
+       else
+               nv_mask(bios, 0x088050, 0x00000001, 0x00000001);
+}
+
+static void *
+prom_init(struct nouveau_bios *bios, const char *name)
+{
+       if (nv_device(bios)->card_type < NV_50) {
+               if (nv_device(bios)->card_type == NV_40 &&
+                   nv_device(bios)->chipset >= 0x4c)
+                       return ERR_PTR(-ENODEV);
+               nv_mask(bios, 0x001850, 0x00000001, 0x00000000);
+       } else {
+               nv_mask(bios, 0x088050, 0x00000001, 0x00000000);
+       }
+       return bios;
+}
+
+const struct nvbios_source
+nvbios_rom = {
+       .name = "PROM",
+       .init = prom_init,
+       .fini = prom_fini,
+       .read = prom_read,
+       .rw = false,
+};
index 46d955eb51eba6f956b238d0134fb2043fec7bd4..8521eca1ed9c576657ba5619d51e24f876e8e52b 100644 (file)
@@ -93,10 +93,44 @@ nvbios_timingEp(struct nouveau_bios *bios, int idx,
        p->timing_hdr = *hdr;
        switch (!!data * *ver) {
        case 0x10:
-               p->timing_10_WR = nv_ro08(bios, data + 0x00);
-               p->timing_10_CL = nv_ro08(bios, data + 0x02);
-               p->timing_10_ODT = nv_ro08(bios, data + 0x0e) & 0x07;
-               p->timing_10_CWL = nv_ro08(bios, data + 0x13);
+               p->timing_10_WR    = nv_ro08(bios, data + 0x00);
+               p->timing_10_WTR   = nv_ro08(bios, data + 0x01);
+               p->timing_10_CL    = nv_ro08(bios, data + 0x02);
+               p->timing_10_RC    = nv_ro08(bios, data + 0x03);
+               p->timing_10_RFC   = nv_ro08(bios, data + 0x05);
+               p->timing_10_RAS   = nv_ro08(bios, data + 0x07);
+               p->timing_10_RP    = nv_ro08(bios, data + 0x09);
+               p->timing_10_RCDRD = nv_ro08(bios, data + 0x0a);
+               p->timing_10_RCDWR = nv_ro08(bios, data + 0x0b);
+               p->timing_10_RRD   = nv_ro08(bios, data + 0x0c);
+               p->timing_10_13    = nv_ro08(bios, data + 0x0d);
+               p->timing_10_ODT   = nv_ro08(bios, data + 0x0e) & 0x07;
+
+               p->timing_10_24  = 0xff;
+               p->timing_10_21  = 0;
+               p->timing_10_20  = 0;
+               p->timing_10_CWL = 0;
+               p->timing_10_18  = 0;
+               p->timing_10_16  = 0;
+
+               switch (min_t(u8, *hdr, 25)) {
+               case 25:
+                       p->timing_10_24  = nv_ro08(bios, data + 0x18);
+               case 24:
+               case 23:
+               case 22:
+                       p->timing_10_21  = nv_ro08(bios, data + 0x15);
+               case 21:
+                       p->timing_10_20  = nv_ro08(bios, data + 0x14);
+               case 20:
+                       p->timing_10_CWL = nv_ro08(bios, data + 0x13);
+               case 19:
+                       p->timing_10_18  = nv_ro08(bios, data + 0x12);
+               case 18:
+               case 17:
+                       p->timing_10_16  = nv_ro08(bios, data + 0x10);
+               }
+
                break;
        case 0x20:
                p->timing[0] = nv_ro32(bios, data + 0x00);
index 425a8d5e9129fa26cb728a342bd3302f9397082c..fb4fad374bdd8cb4ffbb54dbe0979ef983e1dc52 100644 (file)
@@ -109,7 +109,7 @@ struct gk20a_clk_pllg_params {
 };
 
 static const struct gk20a_clk_pllg_params gk20a_pllg_params = {
-       .min_vco = 1000, .max_vco = 1700,
+       .min_vco = 1000, .max_vco = 2064,
        .min_u = 12, .max_u = 38,
        .min_m = 1, .max_m = 255,
        .min_n = 8, .max_n = 255,
@@ -470,76 +470,91 @@ gk20a_pstates[] = {
        {
                .base = {
                        .domain[nv_clk_src_gpc] = 72000,
+                       .voltage = 0,
                },
        },
        {
                .base = {
                        .domain[nv_clk_src_gpc] = 108000,
+                       .voltage = 1,
                },
        },
        {
                .base = {
                        .domain[nv_clk_src_gpc] = 180000,
+                       .voltage = 2,
                },
        },
        {
                .base = {
                        .domain[nv_clk_src_gpc] = 252000,
+                       .voltage = 3,
                },
        },
        {
                .base = {
                        .domain[nv_clk_src_gpc] = 324000,
+                       .voltage = 4,
                },
        },
        {
                .base = {
                        .domain[nv_clk_src_gpc] = 396000,
+                       .voltage = 5,
                },
        },
        {
                .base = {
                        .domain[nv_clk_src_gpc] = 468000,
+                       .voltage = 6,
                },
        },
        {
                .base = {
                        .domain[nv_clk_src_gpc] = 540000,
+                       .voltage = 7,
                },
        },
        {
                .base = {
                        .domain[nv_clk_src_gpc] = 612000,
+                       .voltage = 8,
                },
        },
        {
                .base = {
                        .domain[nv_clk_src_gpc] = 648000,
+                       .voltage = 9,
                },
        },
        {
                .base = {
                        .domain[nv_clk_src_gpc] = 684000,
+                       .voltage = 10,
                },
        },
        {
                .base = {
                        .domain[nv_clk_src_gpc] = 708000,
+                       .voltage = 11,
                },
        },
        {
                .base = {
                        .domain[nv_clk_src_gpc] = 756000,
+                       .voltage = 12,
                },
        },
        {
                .base = {
                        .domain[nv_clk_src_gpc] = 804000,
+                       .voltage = 13,
                },
        },
        {
                .base = {
                        .domain[nv_clk_src_gpc] = 852000,
+                       .voltage = 14,
                },
        },
 };
index 094551d8ad9b44619f9950c30c6553d1f0a5b730..07ad0124767562a484b6ef3746fca714bfaaf516 100644 (file)
@@ -510,7 +510,7 @@ nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        int ret;
 
        ret = nouveau_clock_create(parent, engine, oclass, nva3_domain, NULL, 0,
-                                  false, &priv);
+                                  true, &priv);
        *pobject = nv_object(priv);
        if (ret)
                return ret;
index 239acfe876c3ddb4262d2e696cd4a59e1e06d951..0e45cee82463af6553be67389282cbf74290b009 100644 (file)
@@ -24,8 +24,6 @@
 
 #include <core/option.h>
 
-#include <subdev/bios.h>
-#include <subdev/bios/init.h>
 #include <subdev/vga.h>
 
 #include "priv.h"
@@ -56,7 +54,7 @@ _nouveau_devinit_init(struct nouveau_object *object)
        if (ret)
                return ret;
 
-       ret = nvbios_init(&devinit->base, devinit->post);
+       ret = impl->post(&devinit->base, devinit->post);
        if (ret)
                return ret;
 
index c69bc7f54e371cf7ca016ec929082d6ecd3f3c5e..4ba43d6a1ec8189dae09b6aa6455a5fb6e580229 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "nv50.h"
 
-static u64
+u64
 gm107_devinit_disable(struct nouveau_devinit *devinit)
 {
        struct nv50_devinit_priv *priv = (void *)devinit;
@@ -53,4 +53,5 @@ gm107_devinit_oclass = &(struct nouveau_devinit_impl) {
        },
        .pll_set = nvc0_devinit_pll_set,
        .disable = gm107_devinit_disable,
+       .post = nvbios_init,
 }.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/gm204.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/gm204.c
new file mode 100644 (file)
index 0000000..e44a866
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/pmu.h>
+
+#include "nv50.h"
+
+static void
+pmu_code(struct nv50_devinit_priv *priv, u32 pmu, u32 img, u32 len, bool sec)
+{
+       struct nouveau_bios *bios = nouveau_bios(priv);
+       int i;
+
+       nv_wr32(priv, 0x10a180, 0x01000000 | (sec ? 0x10000000 : 0) | pmu);
+       for (i = 0; i < len; i += 4) {
+               if ((i & 0xff) == 0)
+                       nv_wr32(priv, 0x10a188, (pmu + i) >> 8);
+               nv_wr32(priv, 0x10a184, nv_ro32(bios, img + i));
+       }
+
+       while (i & 0xff) {
+               nv_wr32(priv, 0x10a184, 0x00000000);
+               i += 4;
+       }
+}
+
+static void
+pmu_data(struct nv50_devinit_priv *priv, u32 pmu, u32 img, u32 len)
+{
+       struct nouveau_bios *bios = nouveau_bios(priv);
+       int i;
+
+       nv_wr32(priv, 0x10a1c0, 0x01000000 | pmu);
+       for (i = 0; i < len; i += 4)
+               nv_wr32(priv, 0x10a1c4, nv_ro32(bios, img + i));
+}
+
+static u32
+pmu_args(struct nv50_devinit_priv *priv, u32 argp, u32 argi)
+{
+       nv_wr32(priv, 0x10a1c0, argp);
+       nv_wr32(priv, 0x10a1c0, nv_rd32(priv, 0x10a1c4) + argi);
+       return nv_rd32(priv, 0x10a1c4);
+}
+
+static void
+pmu_exec(struct nv50_devinit_priv *priv, u32 init_addr)
+{
+       nv_wr32(priv, 0x10a104, init_addr);
+       nv_wr32(priv, 0x10a10c, 0x00000000);
+       nv_wr32(priv, 0x10a100, 0x00000002);
+}
+
+static int
+pmu_load(struct nv50_devinit_priv *priv, u8 type, bool post,
+        u32 *init_addr_pmu, u32 *args_addr_pmu)
+{
+       struct nouveau_bios *bios = nouveau_bios(priv);
+       struct nvbios_pmuR pmu;
+
+       if (!nvbios_pmuRm(bios, type, &pmu)) {
+               nv_error(priv, "VBIOS PMU fuc %02x not found\n", type);
+               return -EINVAL;
+       }
+
+       if (!post)
+               return 0;
+
+       pmu_code(priv, pmu.boot_addr_pmu, pmu.boot_addr, pmu.boot_size, false);
+       pmu_code(priv, pmu.code_addr_pmu, pmu.code_addr, pmu.code_size, true);
+       pmu_data(priv, pmu.data_addr_pmu, pmu.data_addr, pmu.data_size);
+
+       if (init_addr_pmu) {
+               *init_addr_pmu = pmu.init_addr_pmu;
+               *args_addr_pmu = pmu.args_addr_pmu;
+               return 0;
+       }
+
+       return pmu_exec(priv, pmu.init_addr_pmu), 0;
+}
+
+static int
+gm204_devinit_post(struct nouveau_subdev *subdev, bool post)
+{
+       struct nv50_devinit_priv *priv = (void *)nouveau_devinit(subdev);
+       struct nouveau_bios *bios = nouveau_bios(priv);
+       struct bit_entry bit_I;
+       u32 init, args;
+       int ret;
+
+       if (bit_entry(bios, 'I', &bit_I) || bit_I.version != 1 ||
+                                           bit_I.length < 0x1c) {
+               nv_error(priv, "VBIOS PMU init data not found\n");
+               return -EINVAL;
+       }
+
+       /* reset PMU and load init table parser ucode */
+       if (post) {
+               nv_mask(priv, 0x000200, 0x00002000, 0x00000000);
+               nv_mask(priv, 0x000200, 0x00002000, 0x00002000);
+               nv_rd32(priv, 0x000200);
+               while (nv_rd32(priv, 0x10a10c) & 0x00000006) {
+               }
+       }
+
+       ret = pmu_load(priv, 0x04, post, &init, &args);
+       if (ret)
+               return ret;
+
+       /* upload first chunk of init data */
+       if (post) {
+               u32 pmu = pmu_args(priv, args + 0x08, 0x08);
+               u32 img = nv_ro16(bios, bit_I.offset + 0x14);
+               u32 len = nv_ro16(bios, bit_I.offset + 0x16);
+               pmu_data(priv, pmu, img, len);
+       }
+
+       /* upload second chunk of init data */
+       if (post) {
+               u32 pmu = pmu_args(priv, args + 0x08, 0x10);
+               u32 img = nv_ro16(bios, bit_I.offset + 0x18);
+               u32 len = nv_ro16(bios, bit_I.offset + 0x1a);
+               pmu_data(priv, pmu, img, len);
+       }
+
+       /* execute init tables */
+       if (post) {
+               nv_wr32(priv, 0x10a040, 0x00005000);
+               pmu_exec(priv, init);
+               while (!(nv_rd32(priv, 0x10a040) & 0x00002000)) {
+               }
+       }
+
+       /* load and execute some other ucode image (bios therm?) */
+       return pmu_load(priv, 0x01, post, NULL, NULL);
+}
+
+struct nouveau_oclass *
+gm204_devinit_oclass = &(struct nouveau_devinit_impl) {
+       .base.handle = NV_SUBDEV(DEVINIT, 0x07),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv50_devinit_ctor,
+               .dtor = _nouveau_devinit_dtor,
+               .init = nv50_devinit_init,
+               .fini = _nouveau_devinit_fini,
+       },
+       .pll_set = nvc0_devinit_pll_set,
+       .disable = gm107_devinit_disable,
+       .post = gm204_devinit_post,
+}.base;
index 052ad690b468da81ec1a95e04eace07834f70c88..65651c50f6ea3ddce07e754bcb2f681ff2af8256 100644 (file)
@@ -464,4 +464,5 @@ nv04_devinit_oclass = &(struct nouveau_devinit_impl) {
        },
        .meminit = nv04_devinit_meminit,
        .pll_set = nv04_devinit_pll_set,
+       .post = nvbios_init,
 }.base;
index 4a19c10e517809ab7b348803481bcb0c0e98a0eb..a2007a3efc4d48d803ca1150fa44741a8b7085cd 100644 (file)
@@ -136,4 +136,5 @@ nv05_devinit_oclass = &(struct nouveau_devinit_impl) {
        },
        .meminit = nv05_devinit_meminit,
        .pll_set = nv04_devinit_pll_set,
+       .post = nvbios_init,
 }.base;
index 3b8d657da2798445f620e9662467df8696304280..178b46f79b502920287a5710d311a9f83d722f92 100644 (file)
@@ -107,4 +107,5 @@ nv10_devinit_oclass = &(struct nouveau_devinit_impl) {
        },
        .meminit = nv10_devinit_meminit,
        .pll_set = nv04_devinit_pll_set,
+       .post = nvbios_init,
 }.base;
index 526d0c6faacd3d2623f1dae3aa2cd1b92087a00e..995dd97af3e923a074dc541603c0d39a03b825f3 100644 (file)
@@ -34,4 +34,5 @@ nv1a_devinit_oclass = &(struct nouveau_devinit_impl) {
                .fini = nv04_devinit_fini,
        },
        .pll_set = nv04_devinit_pll_set,
+       .post = nvbios_init,
 }.base;
index 04bc9732644ccd706c72fdc055d534e61272f625..915089fb46f7965bae615d81b1f3176c306128a0 100644 (file)
@@ -71,4 +71,5 @@ nv20_devinit_oclass = &(struct nouveau_devinit_impl) {
        },
        .meminit = nv20_devinit_meminit,
        .pll_set = nv04_devinit_pll_set,
+       .post = nvbios_init,
 }.base;
index b46c62a1d5d86a9a44a0db88932dacbca6a10598..968334d1dca4a5ac9cbfd9b486488d0467d82256 100644 (file)
@@ -26,6 +26,7 @@
 #include <subdev/bios/dcb.h>
 #include <subdev/bios/disp.h>
 #include <subdev/bios/init.h>
+#include <subdev/ibus.h>
 #include <subdev/vga.h>
 
 #include "nv50.h"
@@ -91,6 +92,7 @@ int
 nv50_devinit_init(struct nouveau_object *object)
 {
        struct nouveau_bios *bios = nouveau_bios(object);
+       struct nouveau_ibus *ibus = nouveau_ibus(object);
        struct nv50_devinit_priv *priv = (void *)object;
        struct nvbios_outp info;
        struct dcb_output outp;
@@ -105,6 +107,13 @@ nv50_devinit_init(struct nouveau_object *object)
                }
        }
 
+       /* some boards appear to require certain priv register timeouts
+        * to be bumped before runing devinit scripts.  not a clue why
+        * the vbios engineers didn't make the scripts just work...
+        */
+       if (priv->base.post && ibus)
+               nv_ofuncs(ibus)->init(nv_object(ibus));
+
        ret = nouveau_devinit_init(&priv->base);
        if (ret)
                return ret;
@@ -160,4 +169,5 @@ nv50_devinit_oclass = &(struct nouveau_devinit_impl) {
        },
        .pll_set = nv50_devinit_pll_set,
        .disable = nv50_devinit_disable,
+       .post = nvbios_init,
 }.base;
index 51d5076333ecefc8ba5167a3a2ccbedbd12a9b4a..f412bb7f780e06020a95100fe2b4bdd07306fdbf 100644 (file)
@@ -18,4 +18,6 @@ int  nva3_devinit_pll_set(struct nouveau_devinit *, u32, u32);
 
 int  nvc0_devinit_pll_set(struct nouveau_devinit *, u32, u32);
 
+u64  gm107_devinit_disable(struct nouveau_devinit *);
+
 #endif
index 787422505d87b934b9f26af17bdab9542896fd47..a7c80ded77cdce591f65c035e8cd69f88db7dc8a 100644 (file)
@@ -60,4 +60,5 @@ nv84_devinit_oclass = &(struct nouveau_devinit_impl) {
        },
        .pll_set = nv50_devinit_pll_set,
        .disable = nv84_devinit_disable,
+       .post = nvbios_init,
 }.base;
index 2b0e963fc6f01358dc2d4c921af0b2ec3e845c43..a773253a17f6041a0b709274cf322933d947268c 100644 (file)
@@ -59,4 +59,5 @@ nv98_devinit_oclass = &(struct nouveau_devinit_impl) {
        },
        .pll_set = nv50_devinit_pll_set,
        .disable = nv98_devinit_disable,
+       .post = nvbios_init,
 }.base;
index 006cf348bda767e8219901ec63c70aadd7d89365..b9cd9e53f760dfaab68806c4bf9b61598acaf452 100644 (file)
@@ -142,4 +142,5 @@ nva3_devinit_oclass = &(struct nouveau_devinit_impl) {
        .pll_set = nva3_devinit_pll_set,
        .disable = nva3_devinit_disable,
        .mmio    = nva3_devinit_mmio,
+       .post = nvbios_init,
 }.base;
index 4fc68d27eff39e2f460f44dd63f89f9218eb3330..3729846a8e5c980e8354c8214d9c87eedad079c3 100644 (file)
@@ -60,4 +60,5 @@ nvaf_devinit_oclass = &(struct nouveau_devinit_impl) {
        },
        .pll_set = nva3_devinit_pll_set,
        .disable = nvaf_devinit_disable,
+       .post = nvbios_init,
 }.base;
index 30c765747eeaebb2c9a1526b31306587d64e4a5e..80bd7f5eda3d0def565711f8c8ba9db54f265bd4 100644 (file)
@@ -115,4 +115,5 @@ nvc0_devinit_oclass = &(struct nouveau_devinit_impl) {
        },
        .pll_set = nvc0_devinit_pll_set,
        .disable = nvc0_devinit_disable,
+       .post = nvbios_init,
 }.base;
index f0e8683ad8405639d0406c3dc7be0dad153395d5..cbcd51852472aa54ab0667bb0b9f3bac03cd2cac 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <subdev/bios.h>
 #include <subdev/bios/pll.h>
+#include <subdev/bios/init.h>
 #include <subdev/clock/pll.h>
 #include <subdev/devinit.h>
 
@@ -12,6 +13,7 @@ struct nouveau_devinit_impl {
        int  (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq);
        u64  (*disable)(struct nouveau_devinit *);
        u32  (*mmio)(struct nouveau_devinit *, u32);
+       int  (*post)(struct nouveau_subdev *, bool);
 };
 
 #define nouveau_devinit_create(p,e,o,d)                                        \
index f009d8a39d9d70f4063ee8df300ba399682c093f..c866148c440fee88d063736545f38cc35fb6bec7 100644 (file)
  */
 
 #include <subdev/bios.h>
-#include <subdev/bios/bit.h>
+#include <subdev/bios/M0203.h>
 
 #include "priv.h"
 
 int
 nouveau_fb_bios_memtype(struct nouveau_bios *bios)
 {
-       struct bit_entry M;
-       u8 ramcfg;
-
-       ramcfg = (nv_rd32(bios, 0x101000) & 0x0000003c) >> 2;
-       if (!bit_entry(bios, 'M', &M) && M.version == 2 && M.length >= 5) {
-               u16 table   = nv_ro16(bios, M.offset + 3);
-               u8  version = nv_ro08(bios, table + 0);
-               u8  header  = nv_ro08(bios, table + 1);
-               u8  record  = nv_ro08(bios, table + 2);
-               u8  entries = nv_ro08(bios, table + 3);
-               if (table && version == 0x10 && ramcfg < entries) {
-                       u16 entry = table + header + (ramcfg * record);
-                       switch (nv_ro08(bios, entry) & 0x0f) {
-                       case 0: return NV_MEM_TYPE_DDR2;
-                       case 1: return NV_MEM_TYPE_DDR3;
-                       case 2: return NV_MEM_TYPE_GDDR3;
-                       case 3: return NV_MEM_TYPE_GDDR5;
-                       default:
-                               break;
-                       }
-
+       const u8 ramcfg = (nv_rd32(bios, 0x101000) & 0x0000003c) >> 2;
+       struct nvbios_M0203E M0203E;
+       u8 ver, hdr;
+
+       if (nvbios_M0203Em(bios, ramcfg, &ver, &hdr, &M0203E)) {
+               switch (M0203E.type) {
+               case M0203E_TYPE_DDR2 : return NV_MEM_TYPE_DDR2;
+               case M0203E_TYPE_DDR3 : return NV_MEM_TYPE_DDR3;
+               case M0203E_TYPE_GDDR3: return NV_MEM_TYPE_GDDR3;
+               case M0203E_TYPE_GDDR5: return NV_MEM_TYPE_GDDR5;
+               default:
+                       nv_warn(bios, "M0203E type %02x\n", M0203E.type);
+                       return NV_MEM_TYPE_UNKNOWN;
                }
        }
 
+       nv_warn(bios, "M0203E not matched!\n");
        return NV_MEM_TYPE_UNKNOWN;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gddr3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gddr3.c
new file mode 100644 (file)
index 0000000..d85a25d
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ *         Roy Spliet <rspliet@eclipso.eu>
+ */
+
+#include <subdev/bios.h>
+#include "priv.h"
+
+struct ramxlat {
+       int id;
+       u8 enc;
+};
+
+static inline int
+ramxlat(const struct ramxlat *xlat, int id)
+{
+       while (xlat->id >= 0) {
+               if (xlat->id == id)
+                       return xlat->enc;
+               xlat++;
+       }
+       return -EINVAL;
+}
+
+static const struct ramxlat
+ramgddr3_cl_lo[] = {
+       { 7, 7 }, { 8, 0 }, { 9, 1 }, { 10, 2 }, { 11, 3 },
+       /* the below are mentioned in some, but not all, gddr3 docs */
+       { 12, 4 }, { 13, 5 }, { 14, 6 },
+       /* XXX: Per Samsung docs, are these used? They overlap with Qimonda */
+       /* { 4, 4 }, { 5, 5 }, { 6, 6 }, { 12, 8 }, { 13, 9 }, { 14, 10 },
+        * { 15, 11 }, */
+       { -1 }
+};
+
+static const struct ramxlat
+ramgddr3_cl_hi[] = {
+       { 10, 2 }, { 11, 3 }, { 12, 4 }, { 13, 5 }, { 14, 6 }, { 15, 7 },
+       { 16, 0 }, { 17, 1 },
+       { -1 }
+};
+
+static const struct ramxlat
+ramgddr3_wr_lo[] = {
+       { 5, 2 }, { 7, 4 }, { 8, 5 }, { 9, 6 }, { 10, 7 },
+       { 11, 0 },
+       /* the below are mentioned in some, but not all, gddr3 docs */
+       { 4, 1 }, { 6, 3 }, { 12, 1 }, { 13 , 2 },
+       { -1 }
+};
+
+int
+nouveau_gddr3_calc(struct nouveau_ram *ram)
+{
+       int CL, WR, CWL, DLL = 0, ODT = 0, hi;
+
+       switch (ram->next->bios.timing_ver) {
+       case 0x10:
+               CWL = ram->next->bios.timing_10_CWL;
+               CL  = ram->next->bios.timing_10_CL;
+               WR  = ram->next->bios.timing_10_WR;
+               DLL = !ram->next->bios.ramcfg_10_DLLoff;
+               ODT = ram->next->bios.timing_10_ODT;
+               break;
+       case 0x20:
+               CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
+               CL  = (ram->next->bios.timing[1] & 0x0000001f) >> 0;
+               WR  = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
+               /* XXX: Get these values from the VBIOS instead */
+               DLL = !(ram->mr[1] & 0x1);
+               ODT =  (ram->mr[1] & 0x004) >> 2 |
+                      (ram->mr[1] & 0x040) >> 5 |
+                      (ram->mr[1] & 0x200) >> 7;
+               break;
+       default:
+               return -ENOSYS;
+       }
+
+       hi = ram->mr[2] & 0x1;
+       CL  = ramxlat(hi ? ramgddr3_cl_hi : ramgddr3_cl_lo, CL);
+       WR  = ramxlat(ramgddr3_wr_lo, WR);
+       if (CL < 0 || CWL < 1 || CWL > 7 || WR < 0)
+               return -EINVAL;
+
+       ram->mr[0] &= ~0xf74;
+       ram->mr[0] |= (CWL & 0x07) << 9;
+       ram->mr[0] |= (CL & 0x07) << 4;
+       ram->mr[0] |= (CL & 0x08) >> 1;
+
+       ram->mr[1] &= ~0x3fc;
+       ram->mr[1] |= (ODT & 0x03) << 2;
+       ram->mr[1] |= (ODT & 0x03) << 8;
+       ram->mr[1] |= (WR  & 0x03) << 4;
+       ram->mr[1] |= (WR  & 0x04) << 5;
+       ram->mr[1] |= !DLL << 6;
+       return 0;
+}
index 60322e906dd403c5b2d206c4590605f612d4ba0d..283863f7aa9bd58ba9403773b40cc28e77aab8c0 100644 (file)
@@ -37,6 +37,7 @@ extern struct nouveau_oclass gm107_ram_oclass;
 
 int nouveau_sddr2_calc(struct nouveau_ram *ram);
 int nouveau_sddr3_calc(struct nouveau_ram *ram);
+int nouveau_gddr3_calc(struct nouveau_ram *ram);
 int nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts);
 
 #define nouveau_fb_create(p,e,c,d)                                             \
index d1fbbe4b00a2a4ef1eeccef2f43b00cfa02c096d..0ac7256443bb0f2e1745052479e233087fb89bb8 100644 (file)
@@ -140,6 +140,20 @@ ramfuc_wait_vblank(struct ramfuc *ram)
        nouveau_memx_wait_vblank(ram->memx);
 }
 
+static inline void
+ramfuc_train(struct ramfuc *ram)
+{
+       nouveau_memx_train(ram->memx);
+}
+
+static inline int
+ramfuc_train_result(struct nouveau_fb *pfb, u32 *result, u32 rsize)
+{
+       struct nouveau_pwr *ppwr = nouveau_pwr(pfb);
+
+       return nouveau_memx_train_result(ppwr, result, rsize);
+}
+
 static inline void
 ramfuc_block(struct ramfuc *ram)
 {
@@ -162,6 +176,8 @@ ramfuc_unblock(struct ramfuc *ram)
 #define ram_wait(s,r,m,d,n)  ramfuc_wait(&(s)->base, (r), (m), (d), (n))
 #define ram_nsec(s,n)        ramfuc_nsec(&(s)->base, (n))
 #define ram_wait_vblank(s)   ramfuc_wait_vblank(&(s)->base)
+#define ram_train(s)         ramfuc_train(&(s)->base)
+#define ram_train_result(s,r,l) ramfuc_train_result((s), (r), (l))
 #define ram_block(s)         ramfuc_block(&(s)->base)
 #define ram_unblock(s)       ramfuc_unblock(&(s)->base)
 
index 3601deca0bd5d01dd81920fc789aa5a96e148950..3b38a538845d70fc9b714c6cda72740942b4dec6 100644 (file)
  * OTHER DEALINGS IN THE SOFTWARE.
  *
  * Authors: Ben Skeggs
+ *         Roy Spliet <rspliet@eclipso.eu>
  */
 
 #include <subdev/bios.h>
 #include <subdev/bios/bit.h>
 #include <subdev/bios/pll.h>
 #include <subdev/bios/rammap.h>
+#include <subdev/bios/M0205.h>
 #include <subdev/bios/timing.h>
 
 #include <subdev/clock/nva3.h>
 #include <subdev/clock/pll.h>
 
+#include <subdev/gpio.h>
+
+#include <subdev/timer.h>
+
+#include <engine/fifo.h>
+
 #include <core/option.h>
 
 #include "ramfuc.h"
 
 #include "nv50.h"
 
+/* XXX: Remove when memx gains GPIO support */
+extern int nv50_gpio_location(int line, u32 *reg, u32 *shift);
+
 struct nva3_ramfuc {
        struct ramfuc base;
+       struct ramfuc_reg r_0x001610;
+       struct ramfuc_reg r_0x001700;
+       struct ramfuc_reg r_0x002504;
        struct ramfuc_reg r_0x004000;
        struct ramfuc_reg r_0x004004;
        struct ramfuc_reg r_0x004018;
        struct ramfuc_reg r_0x004128;
        struct ramfuc_reg r_0x004168;
+       struct ramfuc_reg r_0x100080;
        struct ramfuc_reg r_0x100200;
        struct ramfuc_reg r_0x100210;
        struct ramfuc_reg r_0x100220[9];
+       struct ramfuc_reg r_0x100264;
        struct ramfuc_reg r_0x1002d0;
        struct ramfuc_reg r_0x1002d4;
        struct ramfuc_reg r_0x1002dc;
        struct ramfuc_reg r_0x10053c;
        struct ramfuc_reg r_0x1005a0;
        struct ramfuc_reg r_0x1005a4;
+       struct ramfuc_reg r_0x100700;
        struct ramfuc_reg r_0x100714;
        struct ramfuc_reg r_0x100718;
        struct ramfuc_reg r_0x10071c;
+       struct ramfuc_reg r_0x100720;
        struct ramfuc_reg r_0x100760;
        struct ramfuc_reg r_0x1007a0;
        struct ramfuc_reg r_0x1007e0;
+       struct ramfuc_reg r_0x100da0;
        struct ramfuc_reg r_0x10f804;
        struct ramfuc_reg r_0x1110e0;
        struct ramfuc_reg r_0x111100;
        struct ramfuc_reg r_0x111104;
+       struct ramfuc_reg r_0x1111e0;
+       struct ramfuc_reg r_0x111400;
        struct ramfuc_reg r_0x611200;
        struct ramfuc_reg r_mr[4];
+       struct ramfuc_reg r_gpioFBVREF;
+};
+
+struct nva3_ltrain {
+       enum {
+               NVA3_TRAIN_UNKNOWN,
+               NVA3_TRAIN_UNSUPPORTED,
+               NVA3_TRAIN_ONCE,
+               NVA3_TRAIN_EXEC,
+               NVA3_TRAIN_DONE
+       } state;
+       u32 r_100720;
+       u32 r_1111e0;
+       u32 r_111400;
+       struct nouveau_mem *mem;
 };
 
 struct nva3_ram {
        struct nouveau_ram base;
        struct nva3_ramfuc fuc;
+       struct nva3_ltrain ltrain;
 };
 
+void
+nva3_link_train_calc(u32 *vals, struct nva3_ltrain *train)
+{
+       int i, lo, hi;
+       u8 median[8], bins[4] = {0, 0, 0, 0}, bin = 0, qty = 0;
+
+       for (i = 0; i < 8; i++) {
+               for (lo = 0; lo < 0x40; lo++) {
+                       if (!(vals[lo] & 0x80000000))
+                               continue;
+                       if (vals[lo] & (0x101 << i))
+                               break;
+               }
+
+               if (lo == 0x40)
+                       return;
+
+               for (hi = lo + 1; hi < 0x40; hi++) {
+                       if (!(vals[lo] & 0x80000000))
+                               continue;
+                       if (!(vals[hi] & (0x101 << i))) {
+                               hi--;
+                               break;
+                       }
+               }
+
+               median[i] = ((hi - lo) >> 1) + lo;
+               bins[(median[i] & 0xf0) >> 4]++;
+               median[i] += 0x30;
+       }
+
+       /* Find the best value for 0x1111e0 */
+       for (i = 0; i < 4; i++) {
+               if (bins[i] > qty) {
+                       bin = i + 3;
+                       qty = bins[i];
+               }
+       }
+
+       train->r_100720 = 0;
+       for (i = 0; i < 8; i++) {
+               median[i] = max(median[i], (u8) (bin << 4));
+               median[i] = min(median[i], (u8) ((bin << 4) | 0xf));
+
+               train->r_100720 |= ((median[i] & 0x0f) << (i << 2));
+       }
+
+       train->r_1111e0 = 0x02000000 | (bin * 0x101);
+       train->r_111400 = 0x0;
+}
+
+/*
+ * Link training for (at least) DDR3
+ */
+int
+nva3_link_train(struct nouveau_fb *pfb)
+{
+       struct nouveau_bios *bios = nouveau_bios(pfb);
+       struct nva3_ram *ram = (void *)pfb->ram;
+       struct nouveau_clock *clk = nouveau_clock(pfb);
+       struct nva3_ltrain *train = &ram->ltrain;
+       struct nouveau_device *device = nv_device(pfb);
+       struct nva3_ramfuc *fuc = &ram->fuc;
+       u32 *result, r1700;
+       int ret, i;
+       struct nvbios_M0205T M0205T = { 0 };
+       u8 ver, hdr, cnt, len, snr, ssz;
+       unsigned int clk_current;
+       unsigned long flags;
+       unsigned long *f = &flags;
+
+       if (nouveau_boolopt(device->cfgopt, "NvMemExec", true) != true)
+               return -ENOSYS;
+
+       /* XXX: Multiple partitions? */
+       result = kmalloc(64 * sizeof(u32), GFP_KERNEL);
+       if (!result)
+               return -ENOMEM;
+
+       train->state = NVA3_TRAIN_EXEC;
+
+       /* Clock speeds for training and back */
+       nvbios_M0205Tp(bios, &ver, &hdr, &cnt, &len, &snr, &ssz, &M0205T);
+       if (M0205T.freq == 0)
+               return -ENOENT;
+
+       clk_current = clk->read(clk, nv_clk_src_mem);
+
+       ret = nva3_clock_pre(clk, f);
+       if (ret)
+               goto out;
+
+       /* First: clock up/down */
+       ret = ram->base.calc(pfb, (u32) M0205T.freq * 1000);
+       if (ret)
+               goto out;
+
+       /* Do this *after* calc, eliminates write in script */
+       nv_wr32(pfb, 0x111400, 0x00000000);
+       /* XXX: Magic writes that improve train reliability? */
+       nv_mask(pfb, 0x100674, 0x0000ffff, 0x00000000);
+       nv_mask(pfb, 0x1005e4, 0x0000ffff, 0x00000000);
+       nv_mask(pfb, 0x100b0c, 0x000000ff, 0x00000000);
+       nv_wr32(pfb, 0x100c04, 0x00000400);
+
+       /* Now the training script */
+       r1700 = ram_rd32(fuc, 0x001700);
+
+       ram_mask(fuc, 0x100200, 0x00000800, 0x00000000);
+       ram_wr32(fuc, 0x611200, 0x3300);
+       ram_wait_vblank(fuc);
+       ram_wait(fuc, 0x611200, 0x00000003, 0x00000000, 500000);
+       ram_mask(fuc, 0x001610, 0x00000083, 0x00000003);
+       ram_mask(fuc, 0x100080, 0x00000020, 0x00000000);
+       ram_mask(fuc, 0x10f804, 0x80000000, 0x00000000);
+       ram_wr32(fuc, 0x001700, 0x00000000);
+
+       ram_train(fuc);
+
+       /* Reset */
+       ram_mask(fuc, 0x10f804, 0x80000000, 0x80000000);
+       ram_wr32(fuc, 0x10053c, 0x0);
+       ram_wr32(fuc, 0x100720, train->r_100720);
+       ram_wr32(fuc, 0x1111e0, train->r_1111e0);
+       ram_wr32(fuc, 0x111400, train->r_111400);
+       ram_nuke(fuc, 0x100080);
+       ram_mask(fuc, 0x100080, 0x00000020, 0x00000020);
+       ram_nsec(fuc, 1000);
+
+       ram_wr32(fuc, 0x001700, r1700);
+       ram_mask(fuc, 0x001610, 0x00000083, 0x00000080);
+       ram_wr32(fuc, 0x611200, 0x3330);
+       ram_mask(fuc, 0x100200, 0x00000800, 0x00000800);
+
+       ram_exec(fuc, true);
+
+       ram->base.calc(pfb, clk_current);
+       ram_exec(fuc, true);
+
+       /* Post-processing, avoids flicker */
+       nv_mask(pfb, 0x616308, 0x10, 0x10);
+       nv_mask(pfb, 0x616b08, 0x10, 0x10);
+
+       nva3_clock_post(clk, f);
+
+       ram_train_result(pfb, result, 64);
+       for (i = 0; i < 64; i++)
+               nv_debug(pfb, "Train: %08x", result[i]);
+       nva3_link_train_calc(result, train);
+
+       nv_debug(pfb, "Train: %08x %08x %08x", train->r_100720,
+                       train->r_1111e0, train->r_111400);
+
+       kfree(result);
+
+       train->state = NVA3_TRAIN_DONE;
+
+       return ret;
+
+out:
+       if(ret == -EBUSY)
+               f = NULL;
+
+       train->state = NVA3_TRAIN_UNSUPPORTED;
+
+       nva3_clock_post(clk, f);
+       return ret;
+}
+
+int
+nva3_link_train_init(struct nouveau_fb *pfb)
+{
+       static const u32 pattern[16] = {
+               0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee,
+               0x00000000, 0x11111111, 0x44444444, 0xdddddddd,
+               0x33333333, 0x55555555, 0x77777777, 0x66666666,
+               0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb,
+       };
+       struct nouveau_bios *bios = nouveau_bios(pfb);
+       struct nva3_ram *ram = (void *)pfb->ram;
+       struct nva3_ltrain *train = &ram->ltrain;
+       struct nouveau_mem *mem;
+       struct nvbios_M0205E M0205E;
+       u8 ver, hdr, cnt, len;
+       u32 r001700;
+       int ret, i = 0;
+
+       train->state = NVA3_TRAIN_UNSUPPORTED;
+
+       /* We support type "5"
+        * XXX: training pattern table appears to be unused for this routine */
+       if (!nvbios_M0205Ep(bios, i, &ver, &hdr, &cnt, &len, &M0205E))
+               return -ENOENT;
+
+       if (M0205E.type != 5)
+               return 0;
+
+       train->state = NVA3_TRAIN_ONCE;
+
+       ret = pfb->ram->get(pfb, 0x8000, 0x10000, 0, 0x800, &ram->ltrain.mem);
+       if (ret)
+               return ret;
+
+       mem = ram->ltrain.mem;
+
+       nv_wr32(pfb, 0x100538, 0x10000000 | (mem->offset >> 16));
+       nv_wr32(pfb, 0x1005a8, 0x0000ffff);
+       nv_mask(pfb, 0x10f800, 0x00000001, 0x00000001);
+
+       for (i = 0; i < 0x30; i++) {
+               nv_wr32(pfb, 0x10f8c0, (i << 8) | i);
+               nv_wr32(pfb, 0x10f900, pattern[i % 16]);
+       }
+
+       for (i = 0; i < 0x30; i++) {
+               nv_wr32(pfb, 0x10f8e0, (i << 8) | i);
+               nv_wr32(pfb, 0x10f920, pattern[i % 16]);
+       }
+
+       /* And upload the pattern */
+       r001700 = nv_rd32(pfb, 0x1700);
+       nv_wr32(pfb, 0x1700, mem->offset >> 16);
+       for (i = 0; i < 16; i++)
+               nv_wr32(pfb, 0x700000 + (i << 2), pattern[i]);
+       for (i = 0; i < 16; i++)
+               nv_wr32(pfb, 0x700100 + (i << 2), pattern[i]);
+       nv_wr32(pfb, 0x1700, r001700);
+
+       train->r_100720 = nv_rd32(pfb, 0x100720);
+       train->r_1111e0 = nv_rd32(pfb, 0x1111e0);
+       train->r_111400 = nv_rd32(pfb, 0x111400);
+
+       return 0;
+}
+
+void
+nva3_link_train_fini(struct nouveau_fb *pfb)
+{
+       struct nva3_ram *ram = (void *)pfb->ram;
+
+       if (ram->ltrain.mem)
+               pfb->ram->put(pfb, &ram->ltrain.mem);
+}
+
+/*
+ * RAM reclocking
+ */
+#define T(t) cfg->timing_10_##t
+static int
+nva3_ram_timing_calc(struct nouveau_fb *pfb, u32 *timing)
+{
+       struct nva3_ram *ram = (void *)pfb->ram;
+       struct nvbios_ramcfg *cfg = &ram->base.target.bios;
+       int tUNK_base, tUNK_40_0, prevCL;
+       u32 cur2, cur3, cur7, cur8;
+
+       cur2 = nv_rd32(pfb, 0x100228);
+       cur3 = nv_rd32(pfb, 0x10022c);
+       cur7 = nv_rd32(pfb, 0x10023c);
+       cur8 = nv_rd32(pfb, 0x100240);
+
+
+       switch ((!T(CWL)) * ram->base.type) {
+       case NV_MEM_TYPE_DDR2:
+               T(CWL) = T(CL) - 1;
+               break;
+       case NV_MEM_TYPE_GDDR3:
+               T(CWL) = ((cur2 & 0xff000000) >> 24) + 1;
+               break;
+       }
+
+       prevCL = (cur3 & 0x000000ff) + 1;
+       tUNK_base = ((cur7 & 0x00ff0000) >> 16) - prevCL;
+
+       timing[0] = (T(RP) << 24 | T(RAS) << 16 | T(RFC) << 8 | T(RC));
+       timing[1] = (T(WR) + 1 + T(CWL)) << 24 |
+                   max_t(u8,T(18), 1) << 16 |
+                   (T(WTR) + 1 + T(CWL)) << 8 |
+                   (5 + T(CL) - T(CWL));
+       timing[2] = (T(CWL) - 1) << 24 |
+                   (T(RRD) << 16) |
+                   (T(RCDWR) << 8) |
+                   T(RCDRD);
+       timing[3] = (cur3 & 0x00ff0000) |
+                   (0x30 + T(CL)) << 24 |
+                   (0xb + T(CL)) << 8 |
+                   (T(CL) - 1);
+       timing[4] = T(20) << 24 |
+                   T(21) << 16 |
+                   T(13) << 8 |
+                   T(13);
+       timing[5] = T(RFC) << 24 |
+                   max_t(u8,T(RCDRD), T(RCDWR)) << 16 |
+                   max_t(u8, (T(CWL) + 6), (T(CL) + 2)) << 8 |
+                   T(RP);
+       timing[6] = (0x5a + T(CL)) << 16 |
+                   max_t(u8, 1, (6 - T(CL) + T(CWL))) << 8 |
+                   (0x50 + T(CL) - T(CWL));
+       timing[7] = (cur7 & 0xff000000) |
+                   ((tUNK_base + T(CL)) << 16) |
+                   0x202;
+       timing[8] = cur8 & 0xffffff00;
+
+       switch (ram->base.type) {
+       case NV_MEM_TYPE_DDR2:
+       case NV_MEM_TYPE_GDDR3:
+               tUNK_40_0 = prevCL - (cur8 & 0xff);
+               if (tUNK_40_0 > 0)
+                       timing[8] |= T(CL);
+               break;
+       default:
+               break;
+       }
+
+       nv_debug(pfb, "Entry: 220: %08x %08x %08x %08x\n",
+                       timing[0], timing[1], timing[2], timing[3]);
+       nv_debug(pfb, "  230: %08x %08x %08x %08x\n",
+                       timing[4], timing[5], timing[6], timing[7]);
+       nv_debug(pfb, "  240: %08x\n", timing[8]);
+       return 0;
+}
+#undef T
+
+static void
+nouveau_sddr2_dll_reset(struct nva3_ramfuc *fuc)
+{
+       ram_mask(fuc, mr[0], 0x100, 0x100);
+       ram_nsec(fuc, 1000);
+       ram_mask(fuc, mr[0], 0x100, 0x000);
+       ram_nsec(fuc, 1000);
+}
+
+static void
+nouveau_sddr3_dll_disable(struct nva3_ramfuc *fuc, u32 *mr)
+{
+       u32 mr1_old = ram_rd32(fuc, mr[1]);
+
+       if (!(mr1_old & 0x1)) {
+               ram_wr32(fuc, 0x1002d4, 0x00000001);
+               ram_wr32(fuc, mr[1], mr[1]);
+               ram_nsec(fuc, 1000);
+       }
+}
+
+static void
+nouveau_gddr3_dll_disable(struct nva3_ramfuc *fuc, u32 *mr)
+{
+       u32 mr1_old = ram_rd32(fuc, mr[1]);
+
+       if (!(mr1_old & 0x40)) {
+               ram_wr32(fuc, mr[1], mr[1]);
+               ram_nsec(fuc, 1000);
+       }
+}
+
+static void
+nva3_ram_lock_pll(struct nva3_ramfuc *fuc, struct nva3_clock_info *mclk)
+{
+       ram_wr32(fuc, 0x004004, mclk->pll);
+       ram_mask(fuc, 0x004000, 0x00000001, 0x00000001);
+       ram_mask(fuc, 0x004000, 0x00000010, 0x00000000);
+       ram_wait(fuc, 0x004000, 0x00020000, 0x00020000, 64000);
+       ram_mask(fuc, 0x004000, 0x00000010, 0x00000010);
+}
+
+static void
+nva3_ram_fbvref(struct nva3_ramfuc *fuc, u32 val)
+{
+       struct nouveau_gpio *gpio = nouveau_gpio(fuc->base.pfb);
+       struct dcb_gpio_func func;
+       u32 reg, sh, gpio_val;
+       int ret;
+
+       if (gpio->get(gpio, 0, 0x2e, DCB_GPIO_UNUSED) != val) {
+               ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
+               if (ret)
+                       return;
+
+               nv50_gpio_location(func.line, &reg, &sh);
+               gpio_val = ram_rd32(fuc, gpioFBVREF);
+               if (gpio_val & (8 << sh))
+                       val = !val;
+
+               ram_mask(fuc, gpioFBVREF, (0x3 << sh), ((val | 0x2) << sh));
+               ram_nsec(fuc, 20000);
+       }
+}
+
 static int
 nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
 {
        struct nouveau_bios *bios = nouveau_bios(pfb);
        struct nva3_ram *ram = (void *)pfb->ram;
        struct nva3_ramfuc *fuc = &ram->fuc;
+       struct nva3_ltrain *train = &ram->ltrain;
        struct nva3_clock_info mclk;
        struct nouveau_ram_data *next;
        u8  ver, hdr, cnt, len, strap;
        u32 data;
-       u32 r004018, r100760, ctrl;
+       u32 r004018, r100760, r100da0, r111100, ctrl;
        u32 unk714, unk718, unk71c;
        int ret, i;
+       u32 timing[9];
+       bool pll2pll;
 
        next = &ram->base.target;
        next->freq = freq;
        ram->base.next = next;
 
+       if (ram->ltrain.state == NVA3_TRAIN_ONCE)
+               nva3_link_train(pfb);
+
        /* lookup memory config data relevant to the target frequency */
        i = 0;
-       while ((data = nvbios_rammapEp(bios, i++, &ver, &hdr, &cnt, &len,
-                                     &next->bios))) {
-               if (freq / 1000 >= next->bios.rammap_min &&
-                   freq / 1000 <= next->bios.rammap_max)
-                       break;
-       }
-
-       if (!data || ver != 0x10 || hdr < 0x0e) {
+       data = nvbios_rammapEm(bios, freq / 1000, &ver, &hdr, &cnt, &len,
+                                     &next->bios);
+       if (!data || ver != 0x10 || hdr < 0x05) {
                nv_error(pfb, "invalid/missing rammap entry\n");
                return -EINVAL;
        }
@@ -113,7 +539,7 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
 
        data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, strap,
                               &ver, &hdr, &next->bios);
-       if (!data || ver != 0x10 || hdr < 0x0e) {
+       if (!data || ver != 0x10 || hdr < 0x09) {
                nv_error(pfb, "invalid/missing ramcfg entry\n");
                return -EINVAL;
        }
@@ -123,7 +549,7 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
                data = nvbios_timingEp(bios, next->bios.ramcfg_timing,
                                       &ver, &hdr, &cnt, &len,
                                       &next->bios);
-               if (!data || ver != 0x10 || hdr < 0x19) {
+               if (!data || ver != 0x10 || hdr < 0x17) {
                        nv_error(pfb, "invalid/missing timing entry\n");
                        return -EINVAL;
                }
@@ -135,7 +561,32 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
                return ret;
        }
 
+       nva3_ram_timing_calc(pfb, timing);
+
        ret = ram_init(fuc, pfb);
+       if (ret)
+               return ret;
+
+       /* Determine ram-specific MR values */
+       ram->base.mr[0] = ram_rd32(fuc, mr[0]);
+       ram->base.mr[1] = ram_rd32(fuc, mr[1]);
+       ram->base.mr[2] = ram_rd32(fuc, mr[2]);
+
+       switch (ram->base.type) {
+       case NV_MEM_TYPE_DDR2:
+               ret = nouveau_sddr2_calc(&ram->base);
+               break;
+       case NV_MEM_TYPE_DDR3:
+               ret = nouveau_sddr3_calc(&ram->base);
+               break;
+       case NV_MEM_TYPE_GDDR3:
+               ret = nouveau_gddr3_calc(&ram->base);
+               break;
+       default:
+               ret = -ENOSYS;
+               break;
+       }
+
        if (ret)
                return ret;
 
@@ -143,45 +594,66 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
        if (freq <= 750000) {
                r004018 = 0x10000000;
                r100760 = 0x22222222;
+               r100da0 = 0x00000010;
        } else {
                r004018 = 0x00000000;
                r100760 = 0x00000000;
+               r100da0 = 0x00000000;
        }
 
+       if (!next->bios.ramcfg_10_DLLoff)
+               r004018 |= 0x00004000;
+
+       /* pll2pll requires to switch to a safe clock first */
        ctrl = ram_rd32(fuc, 0x004000);
-       if (ctrl & 0x00000008) {
-               if (mclk.pll) {
-                       ram_mask(fuc, 0x004128, 0x00000101, 0x00000101);
-                       ram_wr32(fuc, 0x004004, mclk.pll);
-                       ram_wr32(fuc, 0x004000, (ctrl |= 0x00000001));
-                       ram_wr32(fuc, 0x004000, (ctrl &= 0xffffffef));
-                       ram_wait(fuc, 0x004000, 0x00020000, 0x00020000, 64000);
-                       ram_wr32(fuc, 0x004000, (ctrl |= 0x00000010));
-                       ram_wr32(fuc, 0x004018, 0x00005000 | r004018);
-                       ram_wr32(fuc, 0x004000, (ctrl |= 0x00000004));
-               }
-       } else {
-               u32 ssel = 0x00000101;
-               if (mclk.clk)
-                       ssel |= mclk.clk;
-               else
-                       ssel |= 0x00080000; /* 324MHz, shouldn't matter... */
-               ram_mask(fuc, 0x004168, 0x003f3141, ctrl);
-       }
+       pll2pll = (!(ctrl & 0x00000008)) && mclk.pll;
 
+       /* Pre, NVIDIA does this outside the script */
        if (next->bios.ramcfg_10_02_10) {
                ram_mask(fuc, 0x111104, 0x00000600, 0x00000000);
        } else {
                ram_mask(fuc, 0x111100, 0x40000000, 0x40000000);
                ram_mask(fuc, 0x111104, 0x00000180, 0x00000000);
        }
+       /* Always disable this bit during reclock */
+       ram_mask(fuc, 0x100200, 0x00000800, 0x00000000);
+
+       /* If switching from non-pll to pll, lock before disabling FB */
+       if (mclk.pll && !pll2pll) {
+               ram_mask(fuc, 0x004128, 0x003f3141, mclk.clk | 0x00000101);
+               nva3_ram_lock_pll(fuc, &mclk);
+       }
+
+       /* Start with disabling some CRTCs and PFIFO? */
+       ram_wait_vblank(fuc);
+       ram_wr32(fuc, 0x611200, 0x3300);
+       ram_mask(fuc, 0x002504, 0x1, 0x1);
+       ram_nsec(fuc, 10000);
+       ram_wait(fuc, 0x002504, 0x10, 0x10, 20000); /* XXX: or longer? */
+       ram_block(fuc);
+       ram_nsec(fuc, 2000);
+
+       if (!next->bios.ramcfg_10_02_10) {
+               if (ram->base.type == NV_MEM_TYPE_GDDR3)
+                       ram_mask(fuc, 0x111100, 0x04020000, 0x00020000);
+               else
+                       ram_mask(fuc, 0x111100, 0x04020000, 0x04020000);
+       }
+
+       /* If we're disabling the DLL, do it now */
+       switch (next->bios.ramcfg_10_DLLoff * ram->base.type) {
+       case NV_MEM_TYPE_DDR3:
+               nouveau_sddr3_dll_disable(fuc, ram->base.mr);
+               break;
+       case NV_MEM_TYPE_GDDR3:
+               nouveau_gddr3_dll_disable(fuc, ram->base.mr);
+               break;
+       }
 
-       if (!next->bios.rammap_10_04_02)
-               ram_mask(fuc, 0x100200, 0x00000800, 0x00000000);
-       ram_wr32(fuc, 0x611200, 0x00003300);
-       if (!next->bios.ramcfg_10_02_10)
-               ram_wr32(fuc, 0x111100, 0x4c020000); /*XXX*/
+       if (fuc->r_gpioFBVREF.addr && next->bios.timing_10_ODT)
+               nva3_ram_fbvref(fuc, 0);
 
+       /* Brace RAM for impact */
        ram_wr32(fuc, 0x1002d4, 0x00000001);
        ram_wr32(fuc, 0x1002d0, 0x00000001);
        ram_wr32(fuc, 0x1002d0, 0x00000001);
@@ -189,24 +661,38 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
        ram_wr32(fuc, 0x1002dc, 0x00000001);
        ram_nsec(fuc, 2000);
 
-       ctrl = ram_rd32(fuc, 0x004000);
-       if (!(ctrl & 0x00000008) && mclk.pll) {
-               ram_wr32(fuc, 0x004000, (ctrl |=  0x00000008));
+       if (nv_device(pfb)->chipset == 0xa3 && freq <= 500000)
+               ram_mask(fuc, 0x100700, 0x00000006, 0x00000006);
+
+       /* Fiddle with clocks */
+       /* There's 4 scenario's
+        * pll->pll: first switch to a 324MHz clock, set up new PLL, switch
+        * clk->pll: Set up new PLL, switch
+        * pll->clk: Set up clock, switch
+        * clk->clk: Overwrite ctrl and other bits, switch */
+
+       /* Switch to regular clock - 324MHz */
+       if (pll2pll) {
+               ram_mask(fuc, 0x004000, 0x00000004, 0x00000004);
+               ram_mask(fuc, 0x004168, 0x003f3141, 0x00083101);
+               ram_mask(fuc, 0x004000, 0x00000008, 0x00000008);
                ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000);
                ram_wr32(fuc, 0x004018, 0x00001000);
-               ram_wr32(fuc, 0x004000, (ctrl &= ~0x00000001));
-               ram_wr32(fuc, 0x004004, mclk.pll);
-               ram_wr32(fuc, 0x004000, (ctrl |=  0x00000001));
-               udelay(64);
-               ram_wr32(fuc, 0x004018, 0x00005000 | r004018);
-               udelay(20);
-       } else
-       if (!mclk.pll) {
-               ram_mask(fuc, 0x004168, 0x003f3040, mclk.clk);
-               ram_wr32(fuc, 0x004000, (ctrl |= 0x00000008));
+               nva3_ram_lock_pll(fuc, &mclk);
+       }
+
+       if (mclk.pll) {
+               ram_mask(fuc, 0x004000, 0x00000105, 0x00000105);
+               ram_wr32(fuc, 0x004018, 0x00001000 | r004018);
+               ram_wr32(fuc, 0x100da0, r100da0);
+       } else {
+               ram_mask(fuc, 0x004168, 0x003f3141, mclk.clk | 0x00000101);
+               ram_mask(fuc, 0x004000, 0x00000108, 0x00000008);
                ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000);
-               ram_wr32(fuc, 0x004018, 0x0000d000 | r004018);
+               ram_wr32(fuc, 0x004018, 0x00009000 | r004018);
+               ram_wr32(fuc, 0x100da0, r100da0);
        }
+       ram_nsec(fuc, 20000);
 
        if (next->bios.rammap_10_04_08) {
                ram_wr32(fuc, 0x1005a0, next->bios.ramcfg_10_06 << 16 |
@@ -220,6 +706,12 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
                                        0x80000000);
                ram_mask(fuc, 0x10053c, 0x00001000, 0x00000000);
        } else {
+               if (train->state == NVA3_TRAIN_DONE) {
+                       ram_wr32(fuc, 0x100080, 0x1020);
+                       ram_mask(fuc, 0x111400, 0xffffffff, train->r_111400);
+                       ram_mask(fuc, 0x1111e0, 0xffffffff, train->r_1111e0);
+                       ram_mask(fuc, 0x100720, 0xffffffff, train->r_100720);
+               }
                ram_mask(fuc, 0x10053c, 0x00001000, 0x00001000);
                ram_mask(fuc, 0x10f804, 0x80000000, 0x00000000);
                ram_mask(fuc, 0x100760, 0x22222222, r100760);
@@ -227,65 +719,131 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
                ram_mask(fuc, 0x1007e0, 0x22222222, r100760);
        }
 
+       if (nv_device(pfb)->chipset == 0xa3 && freq > 500000) {
+               ram_mask(fuc, 0x100700, 0x00000006, 0x00000000);
+       }
+
+       /* Final switch */
        if (mclk.pll) {
                ram_mask(fuc, 0x1110e0, 0x00088000, 0x00011000);
-               ram_wr32(fuc, 0x004000, (ctrl &= ~0x00000008));
+               ram_mask(fuc, 0x004000, 0x00000008, 0x00000000);
        }
 
-       /*XXX: LEAVE */
        ram_wr32(fuc, 0x1002dc, 0x00000000);
        ram_wr32(fuc, 0x1002d4, 0x00000001);
        ram_wr32(fuc, 0x100210, 0x80000000);
-       ram_nsec(fuc, 1000);
-       ram_nsec(fuc, 1000);
+       ram_nsec(fuc, 2000);
 
-       ram_mask(fuc, mr[2], 0x00000000, 0x00000000);
-       ram_nsec(fuc, 1000);
-       ram_nuke(fuc, mr[0]);
-       ram_mask(fuc, mr[0], 0x00000000, 0x00000000);
-       ram_nsec(fuc, 1000);
+       /* Set RAM MR parameters and timings */
+       for (i = 2; i >= 0; i--) {
+               if (ram_rd32(fuc, mr[i]) != ram->base.mr[i]) {
+                       ram_wr32(fuc, mr[i], ram->base.mr[i]);
+                       ram_nsec(fuc, 1000);
+               }
+       }
 
-       ram_mask(fuc, 0x100220[3], 0x00000000, 0x00000000);
-       ram_mask(fuc, 0x100220[1], 0x00000000, 0x00000000);
-       ram_mask(fuc, 0x100220[6], 0x00000000, 0x00000000);
-       ram_mask(fuc, 0x100220[7], 0x00000000, 0x00000000);
-       ram_mask(fuc, 0x100220[2], 0x00000000, 0x00000000);
-       ram_mask(fuc, 0x100220[4], 0x00000000, 0x00000000);
-       ram_mask(fuc, 0x100220[5], 0x00000000, 0x00000000);
-       ram_mask(fuc, 0x100220[0], 0x00000000, 0x00000000);
-       ram_mask(fuc, 0x100220[8], 0x00000000, 0x00000000);
+       ram_wr32(fuc, 0x100220[3], timing[3]);
+       ram_wr32(fuc, 0x100220[1], timing[1]);
+       ram_wr32(fuc, 0x100220[6], timing[6]);
+       ram_wr32(fuc, 0x100220[7], timing[7]);
+       ram_wr32(fuc, 0x100220[2], timing[2]);
+       ram_wr32(fuc, 0x100220[4], timing[4]);
+       ram_wr32(fuc, 0x100220[5], timing[5]);
+       ram_wr32(fuc, 0x100220[0], timing[0]);
+       ram_wr32(fuc, 0x100220[8], timing[8]);
 
+       /* Misc */
        ram_mask(fuc, 0x100200, 0x00001000, !next->bios.ramcfg_10_02_08 << 12);
 
-       unk714 = ram_rd32(fuc, 0x100714) & ~0xf0000010;
-       unk718 = ram_rd32(fuc, 0x100718) & ~0x00000100;
-       unk71c = ram_rd32(fuc, 0x10071c) & ~0x00000100;
+       /* XXX: A lot of "chipset"/"ram type" specific stuff...? */
+       unk714  = ram_rd32(fuc, 0x100714) & ~0xf0000130;
+       unk718  = ram_rd32(fuc, 0x100718) & ~0x00000100;
+       unk71c  = ram_rd32(fuc, 0x10071c) & ~0x00000100;
+       r111100 = ram_rd32(fuc, 0x111100) & ~0x3a800000;
+
+       if (next->bios.ramcfg_10_02_04) {
+               switch (ram->base.type) {
+               case NV_MEM_TYPE_DDR3:
+                       if (nv_device(pfb)->chipset != 0xa8)
+                               r111100 |= 0x00000004;
+                       /* no break */
+               case NV_MEM_TYPE_DDR2:
+                       r111100 |= 0x08000000;
+                       break;
+               default:
+                       break;
+               }
+       } else {
+               switch (ram->base.type) {
+               case NV_MEM_TYPE_DDR2:
+                       r111100 |= 0x1a800000;
+                       unk714  |= 0x00000010;
+                       break;
+               case NV_MEM_TYPE_DDR3:
+                       if (nv_device(pfb)->chipset == 0xa8) {
+                               r111100 |=  0x08000000;
+                       } else {
+                               r111100 &= ~0x00000004;
+                               r111100 |=  0x12800000;
+                       }
+                       unk714  |= 0x00000010;
+                       break;
+               case NV_MEM_TYPE_GDDR3:
+                       r111100 |= 0x30000000;
+                       unk714  |= 0x00000020;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       unk714 |= (next->bios.ramcfg_10_04_01) << 8;
+
        if (next->bios.ramcfg_10_02_20)
                unk714 |= 0xf0000000;
-       if (!next->bios.ramcfg_10_02_04)
-               unk714 |= 0x00000010;
-       ram_wr32(fuc, 0x100714, unk714);
-
+       if (next->bios.ramcfg_10_02_02)
+               unk718 |= 0x00000100;
        if (next->bios.ramcfg_10_02_01)
                unk71c |= 0x00000100;
-       ram_wr32(fuc, 0x10071c, unk71c);
+       if (next->bios.timing_10_24 != 0xff) {
+               unk718 &= ~0xf0000000;
+               unk718 |= next->bios.timing_10_24 << 28;
+       }
+       if (next->bios.ramcfg_10_02_10)
+               r111100 &= ~0x04020000;
 
-       if (next->bios.ramcfg_10_02_02)
-               unk718 |= 0x00000100;
-       ram_wr32(fuc, 0x100718, unk718);
+       ram_mask(fuc, 0x100714, 0xffffffff, unk714);
+       ram_mask(fuc, 0x10071c, 0xffffffff, unk71c);
+       ram_mask(fuc, 0x100718, 0xffffffff, unk718);
+       ram_mask(fuc, 0x111100, 0xffffffff, r111100);
 
-       if (next->bios.ramcfg_10_02_10)
-               ram_wr32(fuc, 0x111100, 0x48000000); /*XXX*/
+       if (fuc->r_gpioFBVREF.addr && !next->bios.timing_10_ODT)
+               nva3_ram_fbvref(fuc, 1);
 
-       ram_mask(fuc, mr[0], 0x100, 0x100);
-       ram_nsec(fuc, 1000);
-       ram_mask(fuc, mr[0], 0x100, 0x000);
-       ram_nsec(fuc, 1000);
+       /* Reset DLL */
+       if (!next->bios.ramcfg_10_DLLoff)
+               nouveau_sddr2_dll_reset(fuc);
 
-       ram_nsec(fuc, 2000);
-       ram_nsec(fuc, 12000);
+       if (ram->base.type == NV_MEM_TYPE_GDDR3) {
+               ram_nsec(fuc, 31000);
+       } else {
+               ram_nsec(fuc, 14000);
+       }
+
+       if (ram->base.type == NV_MEM_TYPE_DDR3) {
+               ram_wr32(fuc, 0x100264, 0x1);
+               ram_nsec(fuc, 2000);
+       }
 
-       ram_wr32(fuc, 0x611200, 0x00003330);
+       ram_nuke(fuc, 0x100700);
+       ram_mask(fuc, 0x100700, 0x01000000, 0x01000000);
+       ram_mask(fuc, 0x100700, 0x01000000, 0x00000000);
+
+       /* Re-enable FB */
+       ram_unblock(fuc);
+       ram_wr32(fuc, 0x611200, 0x3330);
+
+       /* Post fiddlings */
        if (next->bios.rammap_10_04_02)
                ram_mask(fuc, 0x100200, 0x00000800, 0x00000800);
        if (next->bios.ramcfg_10_02_10) {
@@ -313,7 +871,22 @@ nva3_ram_prog(struct nouveau_fb *pfb)
        struct nouveau_device *device = nv_device(pfb);
        struct nva3_ram *ram = (void *)pfb->ram;
        struct nva3_ramfuc *fuc = &ram->fuc;
-       ram_exec(fuc, nouveau_boolopt(device->cfgopt, "NvMemExec", true));
+       bool exec = nouveau_boolopt(device->cfgopt, "NvMemExec", true);
+
+       if (exec) {
+               nv_mask(pfb, 0x001534, 0x2, 0x2);
+
+               ram_exec(fuc, true);
+
+               /* Post-processing, avoids flicker */
+               nv_mask(pfb, 0x002504, 0x1, 0x0);
+               nv_mask(pfb, 0x001534, 0x2, 0x0);
+
+               nv_mask(pfb, 0x616308, 0x10, 0x10);
+               nv_mask(pfb, 0x616b08, 0x10, 0x10);
+       } else {
+               ram_exec(fuc, false);
+       }
        return 0;
 }
 
@@ -330,38 +903,24 @@ nva3_ram_init(struct nouveau_object *object)
 {
        struct nouveau_fb *pfb = (void *)object->parent;
        struct nva3_ram   *ram = (void *)object;
-       int ret, i;
+       int ret;
 
        ret = nouveau_ram_init(&ram->base);
        if (ret)
                return ret;
 
-       /* prepare for ddr link training, and load training patterns */
-       switch (ram->base.type) {
-       case NV_MEM_TYPE_DDR3: {
-               if (nv_device(pfb)->chipset == 0xa8) {
-                       static const u32 pattern[16] = {
-                               0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee,
-                               0x00000000, 0x11111111, 0x44444444, 0xdddddddd,
-                               0x33333333, 0x55555555, 0x77777777, 0x66666666,
-                               0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb,
-                       };
-
-                       nv_wr32(pfb, 0x100538, 0x10001ff6); /*XXX*/
-                       nv_wr32(pfb, 0x1005a8, 0x0000ffff);
-                       nv_mask(pfb, 0x10f800, 0x00000001, 0x00000001);
-                       for (i = 0; i < 0x30; i++) {
-                               nv_wr32(pfb, 0x10f8c0, (i << 8) | i);
-                               nv_wr32(pfb, 0x10f8e0, (i << 8) | i);
-                               nv_wr32(pfb, 0x10f900, pattern[i % 16]);
-                               nv_wr32(pfb, 0x10f920, pattern[i % 16]);
-                       }
-               }
-       }
-               break;
-       default:
-               break;
-       }
+       nva3_link_train_init(pfb);
+
+       return 0;
+}
+
+static int
+nva3_ram_fini(struct nouveau_object *object, bool suspend)
+{
+       struct nouveau_fb *pfb = (void *)object->parent;
+
+       if (!suspend)
+               nva3_link_train_fini(pfb);
 
        return 0;
 }
@@ -371,8 +930,12 @@ nva3_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
              struct nouveau_oclass *oclass, void *data, u32 datasize,
              struct nouveau_object **pobject)
 {
+       struct nouveau_fb *pfb = nouveau_fb(parent);
+       struct nouveau_gpio *gpio = nouveau_gpio(pfb);
+       struct dcb_gpio_func func;
        struct nva3_ram *ram;
        int ret, i;
+       u32 reg, shift;
 
        ret = nv50_ram_create(parent, engine, oclass, &ram);
        *pobject = nv_object(ram);
@@ -380,7 +943,9 @@ nva3_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                return ret;
 
        switch (ram->base.type) {
+       case NV_MEM_TYPE_DDR2:
        case NV_MEM_TYPE_DDR3:
+       case NV_MEM_TYPE_GDDR3:
                ram->base.calc = nva3_ram_calc;
                ram->base.prog = nva3_ram_prog;
                ram->base.tidy = nva3_ram_tidy;
@@ -390,31 +955,41 @@ nva3_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                return 0;
        }
 
+       ram->fuc.r_0x001610 = ramfuc_reg(0x001610);
+       ram->fuc.r_0x001700 = ramfuc_reg(0x001700);
+       ram->fuc.r_0x002504 = ramfuc_reg(0x002504);
        ram->fuc.r_0x004000 = ramfuc_reg(0x004000);
        ram->fuc.r_0x004004 = ramfuc_reg(0x004004);
        ram->fuc.r_0x004018 = ramfuc_reg(0x004018);
        ram->fuc.r_0x004128 = ramfuc_reg(0x004128);
        ram->fuc.r_0x004168 = ramfuc_reg(0x004168);
+       ram->fuc.r_0x100080 = ramfuc_reg(0x100080);
        ram->fuc.r_0x100200 = ramfuc_reg(0x100200);
        ram->fuc.r_0x100210 = ramfuc_reg(0x100210);
        for (i = 0; i < 9; i++)
                ram->fuc.r_0x100220[i] = ramfuc_reg(0x100220 + (i * 4));
+       ram->fuc.r_0x100264 = ramfuc_reg(0x100264);
        ram->fuc.r_0x1002d0 = ramfuc_reg(0x1002d0);
        ram->fuc.r_0x1002d4 = ramfuc_reg(0x1002d4);
        ram->fuc.r_0x1002dc = ramfuc_reg(0x1002dc);
        ram->fuc.r_0x10053c = ramfuc_reg(0x10053c);
        ram->fuc.r_0x1005a0 = ramfuc_reg(0x1005a0);
        ram->fuc.r_0x1005a4 = ramfuc_reg(0x1005a4);
+       ram->fuc.r_0x100700 = ramfuc_reg(0x100700);
        ram->fuc.r_0x100714 = ramfuc_reg(0x100714);
        ram->fuc.r_0x100718 = ramfuc_reg(0x100718);
        ram->fuc.r_0x10071c = ramfuc_reg(0x10071c);
+       ram->fuc.r_0x100720 = ramfuc_reg(0x100720);
        ram->fuc.r_0x100760 = ramfuc_stride(0x100760, 4, ram->base.part_mask);
        ram->fuc.r_0x1007a0 = ramfuc_stride(0x1007a0, 4, ram->base.part_mask);
        ram->fuc.r_0x1007e0 = ramfuc_stride(0x1007e0, 4, ram->base.part_mask);
+       ram->fuc.r_0x100da0 = ramfuc_stride(0x100da0, 4, ram->base.part_mask);
        ram->fuc.r_0x10f804 = ramfuc_reg(0x10f804);
        ram->fuc.r_0x1110e0 = ramfuc_stride(0x1110e0, 4, ram->base.part_mask);
        ram->fuc.r_0x111100 = ramfuc_reg(0x111100);
        ram->fuc.r_0x111104 = ramfuc_reg(0x111104);
+       ram->fuc.r_0x1111e0 = ramfuc_reg(0x1111e0);
+       ram->fuc.r_0x111400 = ramfuc_reg(0x111400);
        ram->fuc.r_0x611200 = ramfuc_reg(0x611200);
 
        if (ram->base.ranks > 1) {
@@ -429,6 +1004,12 @@ nva3_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                ram->fuc.r_mr[3] = ramfuc_reg(0x1002e4);
        }
 
+       ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
+       if (ret == 0) {
+               nv50_gpio_location(func.line, &reg, &shift);
+               ram->fuc.r_gpioFBVREF = ramfuc_reg(reg);
+       }
+
        return 0;
 }
 
@@ -438,6 +1019,6 @@ nva3_ram_oclass = {
                .ctor = nva3_ram_ctor,
                .dtor = _nouveau_ram_dtor,
                .init = nva3_ram_init,
-               .fini = _nouveau_ram_fini,
+               .fini = nva3_ram_fini,
        },
 };
index bb1eb8f3e63918bdbcc82c5eb0b97af3370b7879..252575f3aa290ff4152d507d0de7157aeed407ea 100644 (file)
@@ -66,7 +66,7 @@ nouveau_sddr2_calc(struct nouveau_ram *ram)
        case 0x10:
                CL  = ram->next->bios.timing_10_CL;
                WR  = ram->next->bios.timing_10_WR;
-               DLL = !ram->next->bios.ramcfg_10_02_40;
+               DLL = !ram->next->bios.ramcfg_10_DLLoff;
                ODT = ram->next->bios.timing_10_ODT & 3;
                break;
        case 0x20:
index 83949b11833af46ca1537904691ca7d13112133a..a2dca4869e52f49ba9e012b19ad22e9ed86315cd 100644 (file)
@@ -80,7 +80,7 @@ nouveau_sddr3_calc(struct nouveau_ram *ram)
                CWL = ram->next->bios.timing_10_CWL;
                CL  = ram->next->bios.timing_10_CL;
                WR  = ram->next->bios.timing_10_WR;
-               DLL = !ram->next->bios.ramcfg_10_02_40;
+               DLL = !ram->next->bios.ramcfg_10_DLLoff;
                ODT = ram->next->bios.timing_10_ODT;
                break;
        case 0x20:
index 1864fa98e6b1f6e86017360f954047e7e4799637..2e30d5a62d6e023c110f4b2d41d6cba003b30e99 100644 (file)
@@ -54,7 +54,7 @@ nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match)
        }
 }
 
-static int
+int
 nv50_gpio_location(int line, u32 *reg, u32 *shift)
 {
        const u32 nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
index 2b1bf545e488df2b6b6ff99253e2cb38895de48f..0dc605db7ec8f7ab17d50c7d27ab72b1bc0d3128 100644 (file)
@@ -473,18 +473,56 @@ nouveau_i2c_extdev_sclass[] = {
        nouveau_anx9805_sclass,
 };
 
+static void
+nouveau_i2c_create_port(struct nouveau_i2c *i2c, int index, u8 type,
+                       struct dcb_i2c_entry *info)
+{
+       const struct nouveau_i2c_impl *impl = (void *)nv_oclass(i2c);
+       struct nouveau_oclass *oclass;
+       struct nouveau_object *parent;
+       struct nouveau_object *object;
+       int ret, pad;
+
+       if (info->share != DCB_I2C_UNUSED) {
+               pad    = info->share;
+               oclass = impl->pad_s;
+       } else {
+               if (type != DCB_I2C_NVIO_AUX)
+                       pad = 0x100 + info->drive;
+               else
+                       pad = 0x100 + info->auxch;
+               oclass = impl->pad_x;
+       }
+
+       ret = nouveau_object_ctor(NULL, nv_object(i2c), oclass, NULL, pad,
+                                &parent);
+       if (ret < 0)
+               return;
+
+       oclass = impl->sclass;
+       do {
+               ret = -EINVAL;
+               if (oclass->handle == type) {
+                       ret = nouveau_object_ctor(parent, nv_object(i2c),
+                                                 oclass, info, index,
+                                                &object);
+               }
+       } while (ret && (++oclass)->handle);
+
+       nouveau_object_ref(NULL, &parent);
+}
+
 int
 nouveau_i2c_create_(struct nouveau_object *parent,
                    struct nouveau_object *engine,
                    struct nouveau_oclass *oclass,
                    int length, void **pobject)
 {
-       const struct nouveau_i2c_impl *impl = (void *)oclass;
        struct nouveau_bios *bios = nouveau_bios(parent);
        struct nouveau_i2c *i2c;
        struct nouveau_object *object;
        struct dcb_i2c_entry info;
-       int ret, i, j, index = -1, pad;
+       int ret, i, j, index = -1;
        struct dcb_output outp;
        u8  ver, hdr;
        u32 data;
@@ -507,43 +545,40 @@ nouveau_i2c_create_(struct nouveau_object *parent,
        INIT_LIST_HEAD(&i2c->ports);
 
        while (!dcb_i2c_parse(bios, ++index, &info)) {
-               if (info.type == DCB_I2C_UNUSED)
+               switch (info.type) {
+               case DCB_I2C_NV04_BIT:
+               case DCB_I2C_NV4E_BIT:
+               case DCB_I2C_NVIO_BIT:
+                       nouveau_i2c_create_port(i2c, NV_I2C_PORT(index),
+                                               info.type, &info);
+                       break;
+               case DCB_I2C_NVIO_AUX:
+                       nouveau_i2c_create_port(i2c, NV_I2C_AUX(index),
+                                               info.type, &info);
+                       break;
+               case DCB_I2C_PMGR:
+                       if (info.drive != DCB_I2C_UNUSED) {
+                               nouveau_i2c_create_port(i2c, NV_I2C_PORT(index),
+                                                       DCB_I2C_NVIO_BIT,
+                                                       &info);
+                       }
+                       if (info.auxch != DCB_I2C_UNUSED) {
+                               nouveau_i2c_create_port(i2c, NV_I2C_AUX(index),
+                                                       DCB_I2C_NVIO_AUX,
+                                                       &info);
+                       }
+                       break;
+               case DCB_I2C_UNUSED:
+               default:
                        continue;
-
-               if (info.share != DCB_I2C_UNUSED) {
-                       if (info.type == DCB_I2C_NVIO_AUX)
-                               pad = info.drive;
-                       else
-                               pad = info.share;
-                       oclass = impl->pad_s;
-               } else {
-                       pad = 0x100 + info.drive;
-                       oclass = impl->pad_x;
                }
-
-               ret = nouveau_object_ctor(NULL, *pobject, oclass,
-                                         NULL, pad, &parent);
-               if (ret < 0)
-                       continue;
-
-               oclass = impl->sclass;
-               do {
-                       ret = -EINVAL;
-                       if (oclass->handle == info.type) {
-                               ret = nouveau_object_ctor(parent, *pobject,
-                                                         oclass, &info,
-                                                         index, &object);
-                       }
-               } while (ret && (++oclass)->handle);
-
-               nouveau_object_ref(NULL, &parent);
        }
 
        /* in addition to the busses specified in the i2c table, there
         * may be ddc/aux channels hiding behind external tmds/dp/etc
         * transmitters.
         */
-       index = ((index + 0x0f) / 0x10) * 0x10;
+       index = NV_I2C_EXT(0);
        i = -1;
        while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &outp))) {
                if (!outp.location || !outp.extdev)
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/gm204.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/gm204.c
new file mode 100644 (file)
index 0000000..06a2b87
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nv50.h"
+
+#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
+#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
+
+static void
+auxch_fini(struct nouveau_i2c *aux, int ch)
+{
+       nv_mask(aux, 0x00d954 + (ch * 0x50), 0x00310000, 0x00000000);
+}
+
+static int
+auxch_init(struct nouveau_i2c *aux, int ch)
+{
+       const u32 unksel = 1; /* nfi which to use, or if it matters.. */
+       const u32 ureq = unksel ? 0x00100000 : 0x00200000;
+       const u32 urep = unksel ? 0x01000000 : 0x02000000;
+       u32 ctrl, timeout;
+
+       /* wait up to 1ms for any previous transaction to be done... */
+       timeout = 1000;
+       do {
+               ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
+               udelay(1);
+               if (!timeout--) {
+                       AUX_ERR("begin idle timeout 0x%08x\n", ctrl);
+                       return -EBUSY;
+               }
+       } while (ctrl & 0x03010000);
+
+       /* set some magic, and wait up to 1ms for it to appear */
+       nv_mask(aux, 0x00d954 + (ch * 0x50), 0x00300000, ureq);
+       timeout = 1000;
+       do {
+               ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
+               udelay(1);
+               if (!timeout--) {
+                       AUX_ERR("magic wait 0x%08x\n", ctrl);
+                       auxch_fini(aux, ch);
+                       return -EBUSY;
+               }
+       } while ((ctrl & 0x03000000) != urep);
+
+       return 0;
+}
+
+int
+gm204_aux(struct nouveau_i2c_port *base, bool retry,
+        u8 type, u32 addr, u8 *data, u8 size)
+{
+       struct nouveau_i2c *aux = nouveau_i2c(base);
+       struct nv50_i2c_port *port = (void *)base;
+       u32 ctrl, stat, timeout, retries;
+       u32 xbuf[4] = {};
+       int ch = port->addr;
+       int ret, i;
+
+       AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
+
+       ret = auxch_init(aux, ch);
+       if (ret)
+               goto out;
+
+       stat = nv_rd32(aux, 0x00d958 + (ch * 0x50));
+       if (!(stat & 0x10000000)) {
+               AUX_DBG("sink not detected\n");
+               ret = -ENXIO;
+               goto out;
+       }
+
+       if (!(type & 1)) {
+               memcpy(xbuf, data, size);
+               for (i = 0; i < 16; i += 4) {
+                       AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
+                       nv_wr32(aux, 0x00d930 + (ch * 0x50) + i, xbuf[i / 4]);
+               }
+       }
+
+       ctrl  = nv_rd32(aux, 0x00d954 + (ch * 0x50));
+       ctrl &= ~0x0001f0ff;
+       ctrl |= type << 12;
+       ctrl |= size - 1;
+       nv_wr32(aux, 0x00d950 + (ch * 0x50), addr);
+
+       /* (maybe) retry transaction a number of times on failure... */
+       for (retries = 0; !ret && retries < 32; retries++) {
+               /* reset, and delay a while if this is a retry */
+               nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x80000000 | ctrl);
+               nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x00000000 | ctrl);
+               if (retries)
+                       udelay(400);
+
+               /* transaction request, wait up to 1ms for it to complete */
+               nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x00010000 | ctrl);
+
+               timeout = 1000;
+               do {
+                       ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
+                       udelay(1);
+                       if (!timeout--) {
+                               AUX_ERR("tx req timeout 0x%08x\n", ctrl);
+                               ret = -EIO;
+                               goto out;
+                       }
+               } while (ctrl & 0x00010000);
+               ret = 1;
+
+               /* read status, and check if transaction completed ok */
+               stat = nv_mask(aux, 0x00d958 + (ch * 0x50), 0, 0);
+               if ((stat & 0x000f0000) == 0x00080000 ||
+                   (stat & 0x000f0000) == 0x00020000)
+                       ret = retry ? 0 : 1;
+               if ((stat & 0x00000100))
+                       ret = -ETIMEDOUT;
+               if ((stat & 0x00000e00))
+                       ret = -EIO;
+
+               AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
+       }
+
+       if (type & 1) {
+               for (i = 0; i < 16; i += 4) {
+                       xbuf[i / 4] = nv_rd32(aux, 0x00d940 + (ch * 0x50) + i);
+                       AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
+               }
+               memcpy(data, xbuf, size);
+       }
+
+out:
+       auxch_fini(aux, ch);
+       return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
+}
+
+static const struct nouveau_i2c_func
+gm204_aux_func = {
+       .aux       = gm204_aux,
+};
+
+int
+gm204_aux_port_ctor(struct nouveau_object *parent,
+                   struct nouveau_object *engine,
+                   struct nouveau_oclass *oclass, void *data, u32 index,
+                   struct nouveau_object **pobject)
+{
+       struct dcb_i2c_entry *info = data;
+       struct nv50_i2c_port *port;
+       int ret;
+
+       ret = nouveau_i2c_port_create(parent, engine, oclass, index,
+                                     &nouveau_i2c_aux_algo, &gm204_aux_func,
+                                     &port);
+       *pobject = nv_object(port);
+       if (ret)
+               return ret;
+
+       port->base.aux = info->auxch;
+       port->addr = info->auxch;
+       return 0;
+}
+
+struct nouveau_oclass
+gm204_i2c_sclass[] = {
+       { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
+         .ofuncs = &(struct nouveau_ofuncs) {
+                 .ctor = nvd0_i2c_port_ctor,
+                 .dtor = _nouveau_i2c_port_dtor,
+                 .init = nv50_i2c_port_init,
+                 .fini = _nouveau_i2c_port_fini,
+         },
+       },
+       { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
+         .ofuncs = &(struct nouveau_ofuncs) {
+                 .ctor = gm204_aux_port_ctor,
+                 .dtor = _nouveau_i2c_port_dtor,
+                 .init = _nouveau_i2c_port_init,
+                 .fini = _nouveau_i2c_port_fini,
+         },
+       },
+       {}
+};
+
+struct nouveau_oclass *
+gm204_i2c_oclass = &(struct nouveau_i2c_impl) {
+       .base.handle = NV_SUBDEV(I2C, 0x24),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = _nouveau_i2c_ctor,
+               .dtor = _nouveau_i2c_dtor,
+               .init = _nouveau_i2c_init,
+               .fini = _nouveau_i2c_fini,
+       },
+       .sclass = gm204_i2c_sclass,
+       .pad_x = &nv04_i2c_pad_oclass,
+       .pad_s = &gm204_i2c_pad_oclass,
+       .aux = 8,
+       .aux_stat = nve0_aux_stat,
+       .aux_mask = nve0_aux_mask,
+}.base;
index 5d2a77421c7408f909018a9ef46d0d041208b223..9ef965692fb15e8334a4b5ca06f8b3adf8fa638e 100644 (file)
@@ -10,8 +10,6 @@ struct nv50_i2c_priv {
 struct nv50_i2c_port {
        struct nouveau_i2c_port base;
        u32 addr;
-       u32 ctrl;
-       u32 data;
        u32 state;
 };
 
@@ -29,4 +27,8 @@ int  nv94_aux_port_ctor(struct nouveau_object *, struct nouveau_object *,
 void nv94_i2c_acquire(struct nouveau_i2c_port *);
 void nv94_i2c_release(struct nouveau_i2c_port *);
 
+int  nvd0_i2c_port_ctor(struct nouveau_object *, struct nouveau_object *,
+                       struct nouveau_oclass *, void *, u32,
+                       struct nouveau_object **);
+
 #endif
index f59c3a25546285dfe9304cbc7a86b5319d56a836..e383ee81f4d232dec342b43b0008e0e2867a9324 100644 (file)
@@ -214,10 +214,6 @@ nv94_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        port->state = 7;
        port->addr = nv50_i2c_addr[info->drive];
-       if (info->share != DCB_I2C_UNUSED) {
-               port->ctrl = 0x00e500 + (info->share * 0x50);
-               port->data = 0x0000e001;
-       }
        return 0;
 }
 
@@ -242,13 +238,8 @@ nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       port->base.aux = info->drive;
-       port->addr = info->drive;
-       if (info->share != DCB_I2C_UNUSED) {
-               port->ctrl = 0x00e500 + (info->drive * 0x50);
-               port->data = 0x00002002;
-       }
-
+       port->base.aux = info->auxch;
+       port->addr = info->auxch;
        return 0;
 }
 
index 364ddb1c5f034d527d0f4e8566018ca242e14c10..fd99380502ec5fc679c74b8c378fdfe2cbfeaa6e 100644 (file)
@@ -48,7 +48,7 @@ nvd0_i2c_func = {
        .sense_sda = nvd0_i2c_sense_sda,
 };
 
-static int
+int
 nvd0_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                   struct nouveau_oclass *oclass, void *data, u32 index,
                   struct nouveau_object **pobject)
@@ -66,10 +66,6 @@ nvd0_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        port->state = 0x00000007;
        port->addr = 0x00d014 + (info->drive * 0x20);
-       if (info->share != DCB_I2C_UNUSED) {
-               port->ctrl = 0x00e500 + (info->share * 0x50);
-               port->data = 0x0000e001;
-       }
        return 0;
 }
 
index cae77e1ad8dc9b24c689b3b29669d946372dbcdf..25fe5c2d110e120baafe2a1f310f838c646bd7f0 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "nv50.h"
 
-static void
+void
 nve0_aux_stat(struct nouveau_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx)
 {
        u32 intr = nv_rd32(i2c, 0x00dc60);
@@ -38,7 +38,7 @@ nve0_aux_stat(struct nouveau_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx)
        nv_wr32(i2c, 0x00dc60, intr);
 }
 
-static void
+void
 nve0_aux_mask(struct nouveau_i2c *i2c, u32 type, u32 mask, u32 data)
 {
        u32 temp = nv_rd32(i2c, 0x00dc68), i;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/padgm204.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/padgm204.c
new file mode 100644 (file)
index 0000000..f0e6fbb
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "pad.h"
+
+struct gm204_i2c_pad {
+       struct nvkm_i2c_pad base;
+       int addr;
+};
+
+static int
+gm204_i2c_pad_fini(struct nouveau_object *object, bool suspend)
+{
+       struct nouveau_i2c *i2c = (void *)object->engine;
+       struct gm204_i2c_pad *pad = (void *)object;
+       nv_mask(i2c, 0x00d97c + pad->addr, 0x00000001, 0x00000001);
+       return nvkm_i2c_pad_fini(&pad->base, suspend);
+}
+
+static int
+gm204_i2c_pad_init(struct nouveau_object *object)
+{
+       struct nouveau_i2c *i2c = (void *)object->engine;
+       struct gm204_i2c_pad *pad = (void *)object;
+
+       switch (nv_oclass(pad->base.next)->handle) {
+       case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX):
+               nv_mask(i2c, 0x00d970 + pad->addr, 0x0000c003, 0x00000002);
+               break;
+       case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT):
+       default:
+               nv_mask(i2c, 0x00d970 + pad->addr, 0x0000c003, 0x0000c001);
+               break;
+       }
+
+       nv_mask(i2c, 0x00d97c + pad->addr, 0x00000001, 0x00000000);
+       return nvkm_i2c_pad_init(&pad->base);
+}
+
+static int
+gm204_i2c_pad_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+                 struct nouveau_oclass *oclass, void *data, u32 index,
+                 struct nouveau_object **pobject)
+{
+       struct gm204_i2c_pad *pad;
+       int ret;
+
+       ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad);
+       *pobject = nv_object(pad);
+       if (ret)
+               return ret;
+
+       pad->addr = index * 0x50;;
+       return 0;
+}
+
+struct nouveau_oclass
+gm204_i2c_pad_oclass = {
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = gm204_i2c_pad_ctor,
+               .dtor = _nvkm_i2c_pad_dtor,
+               .init = gm204_i2c_pad_init,
+               .fini = gm204_i2c_pad_fini,
+       },
+};
index 780090b6425a19026b4302962d87d04291b9c34f..4fe7ae3fde4ef0b2fe9695841c3315e7f007e035 100644 (file)
@@ -5,6 +5,7 @@
 
 extern struct nouveau_oclass nv04_i2c_pad_oclass;
 extern struct nouveau_oclass nv94_i2c_pad_oclass;
+extern struct nouveau_oclass gm204_i2c_pad_oclass;
 
 #define nouveau_i2c_port_create(p,e,o,i,a,f,d)                                 \
        nouveau_i2c_port_create_((p), (e), (o), (i), (a), (f),                 \
@@ -82,4 +83,7 @@ struct nouveau_i2c_impl {
 void nv94_aux_stat(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *);
 void nv94_aux_mask(struct nouveau_i2c *, u32, u32, u32);
 
+void nve0_aux_stat(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *);
+void nve0_aux_mask(struct nouveau_i2c *, u32, u32, u32);
+
 #endif
index e89789a53b80101721e1c5e6ea2589edfb642a94..ec03f9a4290b4d72bb796655061f9fe12b011d68 100644 (file)
@@ -50,6 +50,7 @@ handler(WR32  , 0x0000, 0x0002, #memx_func_wr32)
 handler(WAIT  , 0x0004, 0x0000, #memx_func_wait)
 handler(DELAY , 0x0001, 0x0000, #memx_func_delay)
 handler(VBLANK, 0x0001, 0x0000, #memx_func_wait_vblank)
+handler(TRAIN , 0x0000, 0x0000, #memx_func_train)
 memx_func_tail:
 
 .equ #memx_func_size #memx_func_next - #memx_func_head
@@ -63,6 +64,10 @@ memx_ts_end:
 memx_data_head:
 .skip 0x0800
 memx_data_tail:
+
+memx_train_head:
+.skip 0x0100
+memx_train_tail:
 #endif
 
 /******************************************************************************
@@ -257,6 +262,101 @@ memx_func_delay:
        call(nsec)
        ret
 
+// description
+//
+// $r15 - current (memx)
+// $r4  - packet length
+// $r3  - opcode desciption
+// $r0  - zero
+memx_func_train:
+#if NVKM_PPWR_CHIPSET == GT215
+// $r5 - outer loop counter
+// $r6 - inner loop counter
+// $r7 - entry counter (#memx_train_head + $r7)
+       movw $r5 0x3
+       movw $r7 0x0
+
+// Read random memory to wake up... things
+       imm32($r9, 0x700000)
+       nv_rd32($r8,$r9)
+       movw $r14 0x2710
+       call(nsec)
+
+       memx_func_train_loop_outer:
+               mulu $r8 $r5 0x101
+               sethi $r8 0x02000000
+               imm32($r9, 0x1111e0)
+               nv_wr32($r9, $r8)
+               push $r5
+
+               movw $r6 0x0
+               memx_func_train_loop_inner:
+                       movw $r8 0x1111
+                       mulu $r9 $r6 $r8
+                       shl b32 $r8 $r9 0x10
+                       or $r8 $r9
+                       imm32($r9, 0x100720)
+                       nv_wr32($r9, $r8)
+
+                       imm32($r9, 0x100080)
+                       nv_rd32($r8, $r9)
+                       or $r8 $r8 0x20
+                       nv_wr32($r9, $r8)
+
+                       imm32($r9, 0x10053c)
+                       imm32($r8, 0x80003002)
+                       nv_wr32($r9, $r8)
+
+                       imm32($r14, 0x100560)
+                       imm32($r13, 0x80000000)
+                       add b32 $r12 $r13 0
+                       imm32($r11, 0x001e8480)
+                       call(wait)
+
+                       // $r5 - inner inner loop counter
+                       // $r9 - result
+                       movw $r5 0
+                       imm32($r9, 0x8300ffff)
+                       memx_func_train_loop_4x:
+                               imm32($r10, 0x100080)
+                               nv_rd32($r8, $r10)
+                               imm32($r11, 0xffffffdf)
+                               and $r8 $r11
+                               nv_wr32($r10, $r8)
+
+                               imm32($r10, 0x10053c)
+                               imm32($r8, 0x80003002)
+                               nv_wr32($r10, $r8)
+
+                               imm32($r14, 0x100560)
+                               imm32($r13, 0x80000000)
+                               mov b32 $r12 $r13
+                               imm32($r11, 0x00002710)
+                               call(wait)
+
+                               nv_rd32($r13, $r14)
+                               and $r9 $r9 $r13
+
+                               add b32 $r5 1
+                               cmp b16 $r5 0x4
+                               bra l #memx_func_train_loop_4x
+
+                       add b32 $r10 $r7 #memx_train_head
+                       st b32 D[$r10 + 0] $r9
+                       add b32 $r6 1
+                       add b32 $r7 4
+
+                       cmp b16 $r6 0x10
+                       bra l #memx_func_train_loop_inner
+
+               pop $r5
+               add b32 $r5 1
+               cmp b16 $r5 7
+               bra l #memx_func_train_loop_outer
+
+#endif
+       ret
+
 // description
 //
 // $r15 - current (memx)
@@ -307,8 +407,19 @@ memx_exec:
 // $r11 - data1
 // $r0  - zero
 memx_info:
+       cmp b16 $r12 0x1
+       bra e #memx_info_train
+
+       memx_info_data:
        mov $r12 #memx_data_head
        mov $r11 #memx_data_tail - #memx_data_head
+       bra #memx_info_send
+
+       memx_info_train:
+       mov $r12 #memx_train_head
+       mov $r11 #memx_train_tail - #memx_train_head
+
+       memx_info_send:
        call(send)
        ret
 
index 4d278a96b2bbb8459ff0517210967fe4d86dfc01..713e11e2953db613d871c2687ba6862b9fbc6470 100644 (file)
@@ -46,8 +46,8 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x584d454d,
-       0x0000061c,
-       0x0000060e,
+       0x0000062d,
+       0x0000061f,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -68,8 +68,8 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x46524550,
-       0x00000620,
-       0x0000061e,
+       0x00000631,
+       0x0000062f,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -90,8 +90,8 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x5f433249,
-       0x00000a24,
-       0x000008cb,
+       0x00000a35,
+       0x000008dc,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -112,8 +112,8 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x54534554,
-       0x00000a45,
-       0x00000a26,
+       0x00000a56,
+       0x00000a37,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -134,8 +134,8 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x454c4449,
-       0x00000a50,
-       0x00000a4e,
+       0x00000a61,
+       0x00000a5f,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -246,13 +246,15 @@ uint32_t nv108_pwr_data[] = {
        0x00010006,
        0x00000000,
        0x0000057b,
-/* 0x03b8: memx_func_tail */
-/* 0x03b8: memx_ts_start */
+       0x00000007,
        0x00000000,
-/* 0x03bc: memx_ts_end */
+       0x000005c3,
+/* 0x03c4: memx_func_tail */
+/* 0x03c4: memx_ts_start */
        0x00000000,
-/* 0x03c0: memx_data_head */
+/* 0x03c8: memx_ts_end */
        0x00000000,
+/* 0x03cc: memx_data_head */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -764,8 +766,75 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0bc0: memx_data_tail */
-/* 0x0bc0: i2c_scl_map */
+       0x00000000,
+/* 0x0bcc: memx_data_tail */
+/* 0x0bcc: memx_train_head */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0ccc: memx_train_tail */
+/* 0x0ccc: i2c_scl_map */
        0x00000400,
        0x00000800,
        0x00001000,
@@ -776,7 +845,7 @@ uint32_t nv108_pwr_data[] = {
        0x00020000,
        0x00040000,
        0x00080000,
-/* 0x0be8: i2c_sda_map */
+/* 0x0cf4: i2c_sda_map */
        0x00100000,
        0x00200000,
        0x00400000,
@@ -844,9 +913,6 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
 };
 
 uint32_t nv108_pwr_code[] = {
@@ -1215,10 +1281,10 @@ uint32_t nv108_pwr_code[] = {
        0xf40464f0,
        0x2c06f70b,
        0xb50066cf,
-       0x00f8ee06,
+       0x00f8f106,
 /* 0x0500: memx_func_leave */
        0x66cf2c06,
-       0xef06b500,
+       0xf206b500,
        0xe4400406,
        0x0006f607,
 /* 0x0512: memx_func_leave_wait */
@@ -1270,370 +1336,374 @@ uint32_t nv108_pwr_code[] = {
        0x9800f800,
        0x10b6001e,
        0x005d7e04,
-/* 0x05c3: memx_exec */
-       0xf900f800,
-       0xb2d0f9e0,
-/* 0x05cb: memx_exec_next */
-       0x98b2b2c1,
-       0x10b60013,
-       0xf034e704,
-       0xe033e701,
-       0x0132b601,
-       0x980c30f0,
-       0x55f9de35,
-       0x1ef412a6,
-       0xee0b98e5,
-       0xbbef0c98,
-       0xc44b02cb,
-       0x00bbcf07,
-       0xe0fcd0fc,
-       0x0002c27e,
-/* 0x0602: memx_info */
-       0xc04c00f8,
+/* 0x05c3: memx_func_train */
+       0xf800f800,
+/* 0x05c5: memx_exec */
+       0xf9e0f900,
+       0xb2c1b2d0,
+/* 0x05cd: memx_exec_next */
+       0x001398b2,
+       0xe70410b6,
+       0xe701f034,
+       0xb601e033,
+       0x30f00132,
+       0xde35980c,
+       0x12a655f9,
+       0x98e51ef4,
+       0x0c98f10b,
+       0x02cbbbf2,
+       0xcf07c44b,
+       0xd0fc00bb,
+       0xc27ee0fc,
+       0x00f80002,
+/* 0x0604: memx_info */
+       0xf401c670,
+/* 0x060a: memx_info_data */
+       0xcc4c0c0b,
        0x08004b03,
-       0x0002c27e,
-/* 0x060e: memx_recv */
-       0xd6b000f8,
-       0xb20bf401,
-       0xf400d6b0,
-       0x00f8eb0b,
-/* 0x061c: memx_init */
-/* 0x061e: perf_recv */
-       0x00f800f8,
-/* 0x0620: perf_init */
-/* 0x0622: i2c_drive_scl */
-       0x36b000f8,
-       0x0d0bf400,
-       0xf607e040,
-       0x04bd0001,
-/* 0x0632: i2c_drive_scl_lo */
-       0xe44000f8,
-       0x0001f607,
-       0x00f804bd,
-/* 0x063c: i2c_drive_sda */
-       0xf40036b0,
-       0xe0400d0b,
-       0x0002f607,
-       0x00f804bd,
-/* 0x064c: i2c_drive_sda_lo */
-       0xf607e440,
-       0x04bd0002,
-/* 0x0656: i2c_sense_scl */
-       0x32f400f8,
-       0x07c44301,
-       0xfd0033cf,
-       0x0bf40431,
-       0x0131f406,
-/* 0x0668: i2c_sense_scl_done */
-/* 0x066a: i2c_sense_sda */
-       0x32f400f8,
-       0x07c44301,
-       0xfd0033cf,
-       0x0bf40432,
-       0x0131f406,
-/* 0x067c: i2c_sense_sda_done */
-/* 0x067e: i2c_raise_scl */
-       0x40f900f8,
-       0x03089844,
-       0x06227e01,
-/* 0x0689: i2c_raise_scl_wait */
-       0x03e84e00,
-       0x00005d7e,
-       0x0006567e,
-       0xb60901f4,
-       0x1bf40142,
-/* 0x069d: i2c_raise_scl_done */
-       0xf840fcef,
-/* 0x06a1: i2c_start */
-       0x06567e00,
-       0x0d11f400,
-       0x00066a7e,
-       0xf40611f4,
-/* 0x06b2: i2c_start_rep */
-       0x00032e0e,
-       0x0006227e,
-       0x3c7e0103,
-       0x76bb0006,
-       0x0465b600,
-       0x659450f9,
-       0x0256bb04,
-       0x75fd50bd,
-       0x7e50fc04,
-       0xb600067e,
-       0x11f40464,
-/* 0x06dd: i2c_start_send */
-       0x7e00031d,
-       0x4e00063c,
-       0x5d7e1388,
-       0x00030000,
-       0x0006227e,
-       0x7e13884e,
-/* 0x06f7: i2c_start_out */
-       0xf800005d,
-/* 0x06f9: i2c_stop */
-       0x7e000300,
-       0x03000622,
-       0x063c7e00,
-       0x03e84e00,
-       0x00005d7e,
-       0x227e0103,
-       0x884e0006,
-       0x005d7e13,
+/* 0x0613: memx_info_train */
+       0x4c090ef4,
+       0x004b0bcc,
+/* 0x0619: memx_info_send */
+       0x02c27e01,
+/* 0x061f: memx_recv */
+       0xb000f800,
+       0x0bf401d6,
+       0x00d6b0a3,
+       0xf8dc0bf4,
+/* 0x062d: memx_init */
+/* 0x062f: perf_recv */
+       0xf800f800,
+/* 0x0631: perf_init */
+/* 0x0633: i2c_drive_scl */
+       0xb000f800,
+       0x0bf40036,
+       0x07e0400d,
+       0xbd0001f6,
+/* 0x0643: i2c_drive_scl_lo */
+       0x4000f804,
+       0x01f607e4,
+       0xf804bd00,
+/* 0x064d: i2c_drive_sda */
+       0x0036b000,
+       0x400d0bf4,
+       0x02f607e0,
+       0xf804bd00,
+/* 0x065d: i2c_drive_sda_lo */
+       0x07e44000,
+       0xbd0002f6,
+/* 0x0667: i2c_sense_scl */
+       0xf400f804,
+       0xc4430132,
+       0x0033cf07,
+       0xf40431fd,
+       0x31f4060b,
+/* 0x0679: i2c_sense_scl_done */
+/* 0x067b: i2c_sense_sda */
+       0xf400f801,
+       0xc4430132,
+       0x0033cf07,
+       0xf40432fd,
+       0x31f4060b,
+/* 0x068d: i2c_sense_sda_done */
+/* 0x068f: i2c_raise_scl */
+       0xf900f801,
+       0x08984440,
+       0x337e0103,
+/* 0x069a: i2c_raise_scl_wait */
+       0xe84e0006,
+       0x005d7e03,
+       0x06677e00,
+       0x0901f400,
+       0xf40142b6,
+/* 0x06ae: i2c_raise_scl_done */
+       0x40fcef1b,
+/* 0x06b2: i2c_start */
+       0x677e00f8,
+       0x11f40006,
+       0x067b7e0d,
+       0x0611f400,
+/* 0x06c3: i2c_start_rep */
+       0x032e0ef4,
+       0x06337e00,
        0x7e010300,
-       0x4e00063c,
-       0x5d7e1388,
-       0x00f80000,
-/* 0x0728: i2c_bitw */
-       0x00063c7e,
-       0x7e03e84e,
-       0xbb00005d,
+       0xbb00064d,
        0x65b60076,
        0x9450f904,
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x00067e7e,
+       0x00068f7e,
        0xf40464b6,
-       0x884e1711,
-       0x005d7e13,
-       0x7e000300,
-       0x4e000622,
-       0x5d7e1388,
-/* 0x0766: i2c_bitw_out */
-       0x00f80000,
-/* 0x0768: i2c_bitr */
-       0x3c7e0103,
+/* 0x06ee: i2c_start_send */
+       0x00031d11,
+       0x00064d7e,
+       0x7e13884e,
+       0x0300005d,
+       0x06337e00,
+       0x13884e00,
+       0x00005d7e,
+/* 0x0708: i2c_start_out */
+/* 0x070a: i2c_stop */
+       0x000300f8,
+       0x0006337e,
+       0x4d7e0003,
        0xe84e0006,
        0x005d7e03,
-       0x0076bb00,
-       0xf90465b6,
-       0x04659450,
-       0xbd0256bb,
-       0x0475fd50,
-       0x7e7e50fc,
-       0x64b60006,
-       0x1a11f404,
-       0x00066a7e,
-       0x227e0003,
-       0x884e0006,
-       0x005d7e13,
-       0x013cf000,
-/* 0x07ab: i2c_bitr_done */
-       0xf80131f4,
-/* 0x07ad: i2c_get_byte */
-       0x04000500,
-/* 0x07b1: i2c_get_byte_next */
-       0x0154b608,
+       0x7e010300,
+       0x4e000633,
+       0x5d7e1388,
+       0x01030000,
+       0x00064d7e,
+       0x7e13884e,
+       0xf800005d,
+/* 0x0739: i2c_bitw */
+       0x064d7e00,
+       0x03e84e00,
+       0x00005d7e,
        0xb60076bb,
        0x50f90465,
        0xbb046594,
        0x50bd0256,
        0xfc0475fd,
-       0x07687e50,
+       0x068f7e50,
        0x0464b600,
-       0xfd2a11f4,
-       0x42b60553,
-       0xd81bf401,
-       0x76bb0103,
+       0x4e1711f4,
+       0x5d7e1388,
+       0x00030000,
+       0x0006337e,
+       0x7e13884e,
+/* 0x0777: i2c_bitw_out */
+       0xf800005d,
+/* 0x0779: i2c_bitr */
+       0x7e010300,
+       0x4e00064d,
+       0x5d7e03e8,
+       0x76bb0000,
        0x0465b600,
        0x659450f9,
        0x0256bb04,
        0x75fd50bd,
        0x7e50fc04,
-       0xb6000728,
-/* 0x07fa: i2c_get_byte_done */
-       0x00f80464,
-/* 0x07fc: i2c_put_byte */
-/* 0x07fe: i2c_put_byte_next */
-       0x42b60804,
-       0x3854ff01,
-       0xb60076bb,
-       0x50f90465,
-       0xbb046594,
-       0x50bd0256,
-       0xfc0475fd,
-       0x07287e50,
-       0x0464b600,
-       0xb03411f4,
-       0x1bf40046,
-       0x0076bbd8,
+       0xb600068f,
+       0x11f40464,
+       0x067b7e1a,
+       0x7e000300,
+       0x4e000633,
+       0x5d7e1388,
+       0x3cf00000,
+       0x0131f401,
+/* 0x07bc: i2c_bitr_done */
+/* 0x07be: i2c_get_byte */
+       0x000500f8,
+/* 0x07c2: i2c_get_byte_next */
+       0x54b60804,
+       0x0076bb01,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x797e50fc,
+       0x64b60007,
+       0x2a11f404,
+       0xb60553fd,
+       0x1bf40142,
+       0xbb0103d8,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x0007397e,
+/* 0x080b: i2c_get_byte_done */
+       0xf80464b6,
+/* 0x080d: i2c_put_byte */
+/* 0x080f: i2c_put_byte_next */
+       0xb6080400,
+       0x54ff0142,
+       0x0076bb38,
        0xf90465b6,
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
-       0x687e50fc,
+       0x397e50fc,
        0x64b60007,
-       0x0f11f404,
-       0xb00076bb,
-       0x1bf40136,
-       0x0132f406,
-/* 0x0854: i2c_put_byte_done */
-/* 0x0856: i2c_addr */
-       0x76bb00f8,
+       0x3411f404,
+       0xf40046b0,
+       0x76bbd81b,
        0x0465b600,
        0x659450f9,
        0x0256bb04,
        0x75fd50bd,
        0x7e50fc04,
-       0xb60006a1,
+       0xb6000779,
        0x11f40464,
-       0x2ec3e729,
-       0x0134b601,
-       0xbb0553fd,
+       0x0076bb0f,
+       0xf40136b0,
+       0x32f4061b,
+/* 0x0865: i2c_put_byte_done */
+/* 0x0867: i2c_addr */
+       0xbb00f801,
        0x65b60076,
        0x9450f904,
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x0007fc7e,
-/* 0x089b: i2c_addr_done */
-       0xf80464b6,
-/* 0x089d: i2c_acquire_addr */
-       0xf8cec700,
-       0xb705e4b6,
-       0xf8d014e0,
-/* 0x08a9: i2c_acquire */
-       0x089d7e00,
-       0x00047e00,
-       0x03d9f000,
-       0x00002e7e,
-/* 0x08ba: i2c_release */
-       0x9d7e00f8,
+       0x0006b27e,
+       0xf40464b6,
+       0xc3e72911,
+       0x34b6012e,
+       0x0553fd01,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0x080d7e50,
+       0x0464b600,
+/* 0x08ac: i2c_addr_done */
+/* 0x08ae: i2c_acquire_addr */
+       0xcec700f8,
+       0x05e4b6f8,
+       0xd014e0b7,
+/* 0x08ba: i2c_acquire */
+       0xae7e00f8,
        0x047e0008,
-       0xdaf00000,
+       0xd9f00000,
        0x002e7e03,
-/* 0x08cb: i2c_recv */
-       0xf400f800,
-       0xc1c70132,
-       0x0214b6f8,
-       0xf52816b0,
-       0xb801371f,
-       0x000be813,
-       0xb8003298,
-       0x000bc013,
-       0xf4003198,
-       0xd0f90231,
-       0xd0f9e0f9,
-       0x000067f1,
-       0x100063f1,
-       0xbb016792,
+/* 0x08cb: i2c_release */
+       0x7e00f800,
+       0x7e0008ae,
+       0xf0000004,
+       0x2e7e03da,
+       0x00f80000,
+/* 0x08dc: i2c_recv */
+       0xc70132f4,
+       0x14b6f8c1,
+       0x2816b002,
+       0x01371ff5,
+       0x0cf413b8,
+       0x00329800,
+       0x0ccc13b8,
+       0x00319800,
+       0xf90231f4,
+       0xf9e0f9d0,
+       0x0067f1d0,
+       0x0063f100,
+       0x01679210,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0x08ba7e50,
+       0x0464b600,
+       0xd6b0d0fc,
+       0xb01bf500,
+       0xbb000500,
        0x65b60076,
        0x9450f904,
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x0008a97e,
-       0xfc0464b6,
-       0x00d6b0d0,
-       0x00b01bf5,
-       0x76bb0005,
+       0x0008677e,
+       0xf50464b6,
+       0xc700cc11,
+       0x76bbe0c5,
        0x0465b600,
        0x659450f9,
        0x0256bb04,
        0x75fd50bd,
        0x7e50fc04,
-       0xb6000856,
+       0xb600080d,
        0x11f50464,
-       0xc5c700cc,
-       0x0076bbe0,
-       0xf90465b6,
-       0x04659450,
-       0xbd0256bb,
-       0x0475fd50,
-       0xfc7e50fc,
-       0x64b60007,
-       0xa911f504,
-       0xbb010500,
-       0x65b60076,
-       0x9450f904,
-       0x56bb0465,
-       0xfd50bd02,
-       0x50fc0475,
-       0x0008567e,
-       0xf50464b6,
-       0xbb008711,
-       0x65b60076,
-       0x9450f904,
-       0x56bb0465,
-       0xfd50bd02,
-       0x50fc0475,
-       0x0007ad7e,
-       0xf40464b6,
-       0x5bcb6711,
-       0x0076bbe0,
-       0xf90465b6,
-       0x04659450,
-       0xbd0256bb,
-       0x0475fd50,
-       0xf97e50fc,
-       0x64b60006,
-       0xbd5bb204,
-       0x410ef474,
-/* 0x09d0: i2c_recv_not_rd08 */
-       0xf401d6b0,
-       0x00053b1b,
-       0x0008567e,
-       0xc73211f4,
-       0xfc7ee0c5,
-       0x11f40007,
-       0x7e000528,
-       0xf4000856,
-       0xb5c71f11,
-       0x07fc7ee0,
-       0x1511f400,
-       0x0006f97e,
-       0xc5c774bd,
-       0x091bf408,
-       0xf40232f4,
-/* 0x0a0e: i2c_recv_not_wr08 */
-/* 0x0a0e: i2c_recv_done */
-       0xcec7030e,
-       0x08ba7ef8,
-       0xfce0fc00,
-       0x0912f4d0,
-       0xc27e7cb2,
-/* 0x0a22: i2c_recv_exit */
-       0x00f80002,
-/* 0x0a24: i2c_init */
-/* 0x0a26: test_recv */
-       0x584100f8,
-       0x0011cf04,
-       0x400110b6,
-       0x01f60458,
-       0xf104bd00,
-       0xf1d900e7,
-       0x7e134fe3,
-       0xf8000201,
-/* 0x0a45: test_init */
-       0x08004e00,
-       0x0002017e,
-/* 0x0a4e: idle_recv */
-       0x00f800f8,
-/* 0x0a50: idle */
-       0x410031f4,
-       0x11cf0454,
+       0x010500a9,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0x08677e50,
+       0x0464b600,
+       0x008711f5,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0x07be7e50,
+       0x0464b600,
+       0xcb6711f4,
+       0x76bbe05b,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0x7e50fc04,
+       0xb600070a,
+       0x5bb20464,
+       0x0ef474bd,
+/* 0x09e1: i2c_recv_not_rd08 */
+       0x01d6b041,
+       0x053b1bf4,
+       0x08677e00,
+       0x3211f400,
+       0x7ee0c5c7,
+       0xf400080d,
+       0x00052811,
+       0x0008677e,
+       0xc71f11f4,
+       0x0d7ee0b5,
+       0x11f40008,
+       0x070a7e15,
+       0xc774bd00,
+       0x1bf408c5,
+       0x0232f409,
+/* 0x0a1f: i2c_recv_not_wr08 */
+/* 0x0a1f: i2c_recv_done */
+       0xc7030ef4,
+       0xcb7ef8ce,
+       0xe0fc0008,
+       0x12f4d0fc,
+       0x7e7cb209,
+/* 0x0a33: i2c_recv_exit */
+       0xf80002c2,
+/* 0x0a35: i2c_init */
+/* 0x0a37: test_recv */
+       0x4100f800,
+       0x11cf0458,
        0x0110b600,
-       0xf6045440,
+       0xf6045840,
        0x04bd0001,
-/* 0x0a64: idle_loop */
-       0x32f45801,
-/* 0x0a69: idle_proc */
-/* 0x0a69: idle_proc_exec */
-       0xb210f902,
-       0x02cb7e1e,
-       0xf410fc00,
-       0x31f40911,
-       0xf00ef402,
-/* 0x0a7c: idle_proc_next */
-       0xa65810b6,
-       0xe81bf41f,
-       0xf4e002f4,
-       0x0ef40028,
-       0x000000c6,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+       0xd900e7f1,
+       0x134fe3f1,
+       0x0002017e,
+/* 0x0a56: test_init */
+       0x004e00f8,
+       0x02017e08,
+/* 0x0a5f: idle_recv */
+       0xf800f800,
+/* 0x0a61: idle */
+       0x0031f400,
+       0xcf045441,
+       0x10b60011,
+       0x04544001,
+       0xbd0001f6,
+/* 0x0a75: idle_loop */
+       0xf4580104,
+/* 0x0a7a: idle_proc */
+/* 0x0a7a: idle_proc_exec */
+       0x10f90232,
+       0xcb7e1eb2,
+       0x10fc0002,
+       0xf40911f4,
+       0x0ef40231,
+/* 0x0a8d: idle_proc_next */
+       0x5810b6f0,
+       0x1bf41fa6,
+       0xe002f4e8,
+       0xf40028f4,
+       0x0000c60e,
        0x00000000,
        0x00000000,
        0x00000000,
index 64e97baabc3c4d71850641df7a3652d94703bbb4..d1f9b6cb66d7b542979c6f4ad2643be209e7ebe3 100644 (file)
@@ -46,8 +46,8 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x584d454d,
-       0x000006e0,
-       0x000006d2,
+       0x00000842,
+       0x00000834,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -68,8 +68,8 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x46524550,
-       0x000006e4,
-       0x000006e2,
+       0x00000846,
+       0x00000844,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -90,8 +90,8 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x5f433249,
-       0x00000b14,
-       0x000009b7,
+       0x00000c76,
+       0x00000b19,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -112,8 +112,8 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x54534554,
-       0x00000b3d,
-       0x00000b16,
+       0x00000c9f,
+       0x00000c78,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -134,8 +134,8 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x454c4449,
-       0x00000b49,
-       0x00000b47,
+       0x00000cab,
+       0x00000ca9,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -246,13 +246,15 @@ uint32_t nva3_pwr_data[] = {
        0x00010006,
        0x00000000,
        0x000005f8,
-/* 0x03b8: memx_func_tail */
-/* 0x03b8: memx_ts_start */
+       0x00000007,
        0x00000000,
-/* 0x03bc: memx_ts_end */
+       0x0000067e,
+/* 0x03c4: memx_func_tail */
+/* 0x03c4: memx_ts_start */
        0x00000000,
-/* 0x03c0: memx_data_head */
+/* 0x03c8: memx_ts_end */
        0x00000000,
+/* 0x03cc: memx_data_head */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -764,8 +766,75 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0bc0: memx_data_tail */
-/* 0x0bc0: i2c_scl_map */
+       0x00000000,
+/* 0x0bcc: memx_data_tail */
+/* 0x0bcc: memx_train_head */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0ccc: memx_train_tail */
+/* 0x0ccc: i2c_scl_map */
        0x00001000,
        0x00004000,
        0x00010000,
@@ -776,7 +845,7 @@ uint32_t nva3_pwr_data[] = {
        0x01000000,
        0x04000000,
        0x10000000,
-/* 0x0be8: i2c_sda_map */
+/* 0x0cf4: i2c_sda_map */
        0x00002000,
        0x00008000,
        0x00020000,
@@ -787,7 +856,7 @@ uint32_t nva3_pwr_data[] = {
        0x02000000,
        0x08000000,
        0x20000000,
-/* 0x0c10: i2c_ctrl */
+/* 0x0d1c: i2c_ctrl */
        0x0000e138,
        0x0000e150,
        0x0000e168,
@@ -845,9 +914,6 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
 };
 
 uint32_t nva3_pwr_code[] = {
@@ -1258,11 +1324,11 @@ uint32_t nva3_pwr_code[] = {
        0x67f0f30b,
        0x0664b62c,
        0x800066cf,
-       0x00f8ee06,
+       0x00f8f106,
 /* 0x05a8: memx_func_leave */
        0xb62c67f0,
        0x66cf0664,
-       0xef068000,
+       0xf2068000,
        0xf10467f0,
        0xb607e407,
        0x06d00604,
@@ -1323,408 +1389,479 @@ uint32_t nva3_pwr_code[] = {
        0x9800f8a4,
        0x10b6001e,
        0x7f21f404,
-/* 0x067e: memx_exec */
-       0xe0f900f8,
-       0xc1b9d0f9,
-       0x02b2b902,
-/* 0x0688: memx_exec_next */
-       0xb6001398,
-       0x34e70410,
-       0x33e701f0,
-       0x32b601e0,
-       0x0c30f001,
-       0xf9de3598,
-       0x0612b855,
-       0x98e41ef4,
-       0x0c98ee0b,
-       0x02cbbbef,
-       0x07c4b7f1,
-       0xcf06b4b6,
-       0xd0fc00bb,
-       0x21f5e0fc,
+/* 0x067e: memx_func_train */
+       0x57f100f8,
+       0x77f10003,
+       0x97f10000,
+       0x93f00000,
+       0x029eb970,
+       0xb90421f4,
+       0xe7f102d8,
+       0x21f42710,
+/* 0x069d: memx_func_train_loop_outer */
+       0x0158e07f,
+       0x0083f101,
+       0xe097f102,
+       0x1193f011,
+       0x80f990f9,
+       0xe0fcd0fc,
+       0xf93f21f4,
+       0x0067f150,
+/* 0x06bd: memx_func_train_loop_inner */
+       0x1187f100,
+       0x9068ff11,
+       0xfd109894,
+       0x97f10589,
+       0x93f00720,
+       0xf990f910,
+       0xfcd0fc80,
+       0x3f21f4e0,
+       0x008097f1,
+       0xb91093f0,
+       0x21f4029e,
+       0x02d8b904,
+       0xf92088c5,
+       0xfc80f990,
+       0xf4e0fcd0,
+       0x97f13f21,
+       0x93f0053c,
+       0x0287f110,
+       0x0083f130,
+       0xf990f980,
+       0xfcd0fc80,
+       0x3f21f4e0,
+       0x0560e7f1,
+       0xf110e3f0,
+       0xf10000d7,
+       0x908000d3,
+       0xb7f100dc,
+       0xb3f08480,
+       0xa421f41e,
+       0x000057f1,
+       0xffff97f1,
+       0x830093f1,
+/* 0x073c: memx_func_train_loop_4x */
+       0x0080a7f1,
+       0xb910a3f0,
+       0x21f402ae,
+       0x02d8b904,
+       0xffdfb7f1,
+       0xffffb3f1,
+       0xf9048bfd,
+       0xfc80f9a0,
+       0xf4e0fcd0,
+       0xa7f13f21,
+       0xa3f0053c,
+       0x0287f110,
+       0x0083f130,
+       0xf9a0f980,
+       0xfcd0fc80,
+       0x3f21f4e0,
+       0x0560e7f1,
+       0xf110e3f0,
+       0xf10000d7,
+       0xb98000d3,
+       0xb7f102dc,
+       0xb3f02710,
+       0xa421f400,
+       0xf402eeb9,
+       0xddb90421,
+       0x949dff02,
+       0x700150b6,
+       0x1ef40456,
+       0xcc7aa092,
+       0x00a9800b,
+       0xb60160b6,
+       0x66700470,
+       0x001ef510,
+       0xb650fcff,
+       0x56700150,
+       0xd41ef507,
+/* 0x07cf: memx_exec */
+       0xf900f8fe,
+       0xb9d0f9e0,
+       0xb2b902c1,
+/* 0x07d9: memx_exec_next */
+       0x00139802,
+       0xe70410b6,
+       0xe701f034,
+       0xb601e033,
+       0x30f00132,
+       0xde35980c,
+       0x12b855f9,
+       0xe41ef406,
+       0x98f10b98,
+       0xcbbbf20c,
+       0xc4b7f102,
+       0x06b4b607,
+       0xfc00bbcf,
+       0xf5e0fcd0,
+       0xf8034221,
+/* 0x0815: memx_info */
+       0x01c67000,
+/* 0x081b: memx_info_data */
+       0xf10e0bf4,
+       0xf103ccc7,
+       0xf40800b7,
+/* 0x0826: memx_info_train */
+       0xc7f10b0e,
+       0xb7f10bcc,
+/* 0x082e: memx_info_send */
+       0x21f50100,
        0x00f80342,
-/* 0x06c4: memx_info */
-       0x03c0c7f1,
-       0x0800b7f1,
-       0x034221f5,
-/* 0x06d2: memx_recv */
-       0xd6b000f8,
-       0xa90bf401,
-       0xf400d6b0,
-       0x00f8e90b,
-/* 0x06e0: memx_init */
-/* 0x06e2: perf_recv */
+/* 0x0834: memx_recv */
+       0xf401d6b0,
+       0xd6b0980b,
+       0xd80bf400,
+/* 0x0842: memx_init */
+       0x00f800f8,
+/* 0x0844: perf_recv */
+/* 0x0846: perf_init */
        0x00f800f8,
-/* 0x06e4: perf_init */
-/* 0x06e6: i2c_drive_scl */
+/* 0x0848: i2c_drive_scl */
+       0xf40036b0,
+       0x07f1110b,
+       0x04b607e0,
+       0x0001d006,
+       0x00f804bd,
+/* 0x085c: i2c_drive_scl_lo */
+       0x07e407f1,
+       0xd00604b6,
+       0x04bd0001,
+/* 0x086a: i2c_drive_sda */
        0x36b000f8,
        0x110bf400,
        0x07e007f1,
        0xd00604b6,
-       0x04bd0001,
-/* 0x06fa: i2c_drive_scl_lo */
+       0x04bd0002,
+/* 0x087e: i2c_drive_sda_lo */
        0x07f100f8,
        0x04b607e4,
-       0x0001d006,
-       0x00f804bd,
-/* 0x0708: i2c_drive_sda */
-       0xf40036b0,
-       0x07f1110b,
-       0x04b607e0,
        0x0002d006,
        0x00f804bd,
-/* 0x071c: i2c_drive_sda_lo */
-       0x07e407f1,
-       0xd00604b6,
-       0x04bd0002,
-/* 0x072a: i2c_sense_scl */
-       0x32f400f8,
-       0xc437f101,
-       0x0634b607,
-       0xfd0033cf,
-       0x0bf40431,
-       0x0131f406,
-/* 0x0740: i2c_sense_scl_done */
-/* 0x0742: i2c_sense_sda */
-       0x32f400f8,
-       0xc437f101,
-       0x0634b607,
-       0xfd0033cf,
-       0x0bf40432,
-       0x0131f406,
-/* 0x0758: i2c_sense_sda_done */
-/* 0x075a: i2c_raise_scl */
-       0x40f900f8,
-       0x089847f1,
-       0xf50137f0,
-/* 0x0767: i2c_raise_scl_wait */
-       0xf106e621,
-       0xf403e8e7,
-       0x21f57f21,
-       0x01f4072a,
-       0x0142b609,
-/* 0x077b: i2c_raise_scl_done */
-       0xfcef1bf4,
-/* 0x077f: i2c_start */
-       0xf500f840,
-       0xf4072a21,
-       0x21f50d11,
-       0x11f40742,
-       0x300ef406,
-/* 0x0790: i2c_start_rep */
-       0xf50037f0,
-       0xf006e621,
-       0x21f50137,
-       0x76bb0708,
-       0x0465b600,
-       0x659450f9,
-       0x0256bb04,
-       0x75fd50bd,
-       0xf550fc04,
-       0xb6075a21,
-       0x11f40464,
-/* 0x07bd: i2c_start_send */
-       0x0037f01f,
-       0x070821f5,
-       0x1388e7f1,
-       0xf07f21f4,
-       0x21f50037,
-       0xe7f106e6,
-       0x21f41388,
-/* 0x07d9: i2c_start_out */
-/* 0x07db: i2c_stop */
-       0xf000f87f,
-       0x21f50037,
-       0x37f006e6,
-       0x0821f500,
-       0xe8e7f107,
+/* 0x088c: i2c_sense_scl */
+       0xf10132f4,
+       0xb607c437,
+       0x33cf0634,
+       0x0431fd00,
+       0xf4060bf4,
+/* 0x08a2: i2c_sense_scl_done */
+       0x00f80131,
+/* 0x08a4: i2c_sense_sda */
+       0xf10132f4,
+       0xb607c437,
+       0x33cf0634,
+       0x0432fd00,
+       0xf4060bf4,
+/* 0x08ba: i2c_sense_sda_done */
+       0x00f80131,
+/* 0x08bc: i2c_raise_scl */
+       0x47f140f9,
+       0x37f00898,
+       0x4821f501,
+/* 0x08c9: i2c_raise_scl_wait */
+       0xe8e7f108,
        0x7f21f403,
-       0xf50137f0,
-       0xf106e621,
-       0xf41388e7,
-       0x37f07f21,
-       0x0821f501,
-       0x88e7f107,
-       0x7f21f413,
-/* 0x080e: i2c_bitw */
-       0x21f500f8,
-       0xe7f10708,
-       0x21f403e8,
-       0x0076bb7f,
-       0xf90465b6,
-       0x04659450,
-       0xbd0256bb,
-       0x0475fd50,
-       0x21f550fc,
-       0x64b6075a,
-       0x1811f404,
-       0x1388e7f1,
-       0xf07f21f4,
+       0x088c21f5,
+       0xb60901f4,
+       0x1bf40142,
+/* 0x08dd: i2c_raise_scl_done */
+       0xf840fcef,
+/* 0x08e1: i2c_start */
+       0x8c21f500,
+       0x0d11f408,
+       0x08a421f5,
+       0xf40611f4,
+/* 0x08f2: i2c_start_rep */
+       0x37f0300e,
+       0x4821f500,
+       0x0137f008,
+       0x086a21f5,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0xbc21f550,
+       0x0464b608,
+/* 0x091f: i2c_start_send */
+       0xf01f11f4,
        0x21f50037,
-       0xe7f106e6,
+       0xe7f1086a,
        0x21f41388,
-/* 0x084d: i2c_bitw_out */
-/* 0x084f: i2c_bitr */
-       0xf000f87f,
-       0x21f50137,
-       0xe7f10708,
-       0x21f403e8,
-       0x0076bb7f,
-       0xf90465b6,
-       0x04659450,
-       0xbd0256bb,
-       0x0475fd50,
-       0x21f550fc,
-       0x64b6075a,
-       0x1b11f404,
-       0x074221f5,
+       0x0037f07f,
+       0x084821f5,
+       0x1388e7f1,
+/* 0x093b: i2c_start_out */
+       0xf87f21f4,
+/* 0x093d: i2c_stop */
+       0x0037f000,
+       0x084821f5,
        0xf50037f0,
-       0xf106e621,
+       0xf1086a21,
+       0xf403e8e7,
+       0x37f07f21,
+       0x4821f501,
+       0x88e7f108,
+       0x7f21f413,
+       0xf50137f0,
+       0xf1086a21,
        0xf41388e7,
-       0x3cf07f21,
-       0x0131f401,
-/* 0x0894: i2c_bitr_done */
-/* 0x0896: i2c_get_byte */
-       0x57f000f8,
-       0x0847f000,
-/* 0x089c: i2c_get_byte_next */
-       0xbb0154b6,
+       0x00f87f21,
+/* 0x0970: i2c_bitw */
+       0x086a21f5,
+       0x03e8e7f1,
+       0xbb7f21f4,
        0x65b60076,
        0x9450f904,
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x084f21f5,
+       0x08bc21f5,
        0xf40464b6,
-       0x53fd2b11,
-       0x0142b605,
-       0xf0d81bf4,
-       0x76bb0137,
-       0x0465b600,
-       0x659450f9,
-       0x0256bb04,
-       0x75fd50bd,
-       0xf550fc04,
-       0xb6080e21,
-/* 0x08e6: i2c_get_byte_done */
-       0x00f80464,
-/* 0x08e8: i2c_put_byte */
-/* 0x08eb: i2c_put_byte_next */
-       0xb60847f0,
-       0x54ff0142,
-       0x0076bb38,
+       0xe7f11811,
+       0x21f41388,
+       0x0037f07f,
+       0x084821f5,
+       0x1388e7f1,
+/* 0x09af: i2c_bitw_out */
+       0xf87f21f4,
+/* 0x09b1: i2c_bitr */
+       0x0137f000,
+       0x086a21f5,
+       0x03e8e7f1,
+       0xbb7f21f4,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x08bc21f5,
+       0xf40464b6,
+       0x21f51b11,
+       0x37f008a4,
+       0x4821f500,
+       0x88e7f108,
+       0x7f21f413,
+       0xf4013cf0,
+/* 0x09f6: i2c_bitr_done */
+       0x00f80131,
+/* 0x09f8: i2c_get_byte */
+       0xf00057f0,
+/* 0x09fe: i2c_get_byte_next */
+       0x54b60847,
+       0x0076bb01,
        0xf90465b6,
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
        0x21f550fc,
-       0x64b6080e,
-       0x3411f404,
-       0xf40046b0,
-       0x76bbd81b,
-       0x0465b600,
-       0x659450f9,
-       0x0256bb04,
-       0x75fd50bd,
-       0xf550fc04,
-       0xb6084f21,
-       0x11f40464,
-       0x0076bb0f,
-       0xf40136b0,
-       0x32f4061b,
-/* 0x0941: i2c_put_byte_done */
-/* 0x0943: i2c_addr */
-       0xbb00f801,
+       0x64b609b1,
+       0x2b11f404,
+       0xb60553fd,
+       0x1bf40142,
+       0x0137f0d8,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0x7021f550,
+       0x0464b609,
+/* 0x0a48: i2c_get_byte_done */
+/* 0x0a4a: i2c_put_byte */
+       0x47f000f8,
+/* 0x0a4d: i2c_put_byte_next */
+       0x0142b608,
+       0xbb3854ff,
        0x65b60076,
        0x9450f904,
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x077f21f5,
+       0x097021f5,
        0xf40464b6,
-       0xc3e72911,
-       0x34b6012e,
-       0x0553fd01,
+       0x46b03411,
+       0xd81bf400,
        0xb60076bb,
        0x50f90465,
        0xbb046594,
        0x50bd0256,
        0xfc0475fd,
-       0xe821f550,
-       0x0464b608,
-/* 0x0988: i2c_addr_done */
-/* 0x098a: i2c_acquire_addr */
-       0xcec700f8,
-       0x02e4b6f8,
-       0x0c10e0b7,
-       0xf800ee98,
-/* 0x0999: i2c_acquire */
-       0x8a21f500,
-       0x0421f409,
-       0xf403d9f0,
-       0x00f83f21,
-/* 0x09a8: i2c_release */
-       0x098a21f5,
-       0xf00421f4,
-       0x21f403da,
-/* 0x09b7: i2c_recv */
-       0xf400f83f,
-       0xc1c70132,
-       0x0214b6f8,
-       0xf52816b0,
-       0xa0013a1f,
-       0x980be813,
-       0x13a00032,
-       0x31980bc0,
-       0x0231f400,
-       0xe0f9d0f9,
-       0x67f1d0f9,
-       0x63f10000,
-       0x67921000,
-       0x0076bb01,
-       0xf90465b6,
-       0x04659450,
-       0xbd0256bb,
-       0x0475fd50,
-       0x21f550fc,
-       0x64b60999,
-       0xb0d0fc04,
-       0x1bf500d6,
-       0x57f000b3,
+       0xb121f550,
+       0x0464b609,
+       0xbb0f11f4,
+       0x36b00076,
+       0x061bf401,
+/* 0x0aa3: i2c_put_byte_done */
+       0xf80132f4,
+/* 0x0aa5: i2c_addr */
        0x0076bb00,
        0xf90465b6,
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
        0x21f550fc,
-       0x64b60943,
-       0xd011f504,
-       0xe0c5c700,
-       0xb60076bb,
-       0x50f90465,
-       0xbb046594,
-       0x50bd0256,
-       0xfc0475fd,
-       0xe821f550,
-       0x0464b608,
-       0x00ad11f5,
-       0xbb0157f0,
+       0x64b608e1,
+       0x2911f404,
+       0x012ec3e7,
+       0xfd0134b6,
+       0x76bb0553,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0xf550fc04,
+       0xb60a4a21,
+/* 0x0aea: i2c_addr_done */
+       0x00f80464,
+/* 0x0aec: i2c_acquire_addr */
+       0xb6f8cec7,
+       0xe0b702e4,
+       0xee980d1c,
+/* 0x0afb: i2c_acquire */
+       0xf500f800,
+       0xf40aec21,
+       0xd9f00421,
+       0x3f21f403,
+/* 0x0b0a: i2c_release */
+       0x21f500f8,
+       0x21f40aec,
+       0x03daf004,
+       0xf83f21f4,
+/* 0x0b19: i2c_recv */
+       0x0132f400,
+       0xb6f8c1c7,
+       0x16b00214,
+       0x3a1ff528,
+       0xf413a001,
+       0x0032980c,
+       0x0ccc13a0,
+       0xf4003198,
+       0xd0f90231,
+       0xd0f9e0f9,
+       0x000067f1,
+       0x100063f1,
+       0xbb016792,
        0x65b60076,
        0x9450f904,
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x094321f5,
-       0xf50464b6,
-       0xbb008a11,
+       0x0afb21f5,
+       0xfc0464b6,
+       0x00d6b0d0,
+       0x00b31bf5,
+       0xbb0057f0,
        0x65b60076,
        0x9450f904,
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x089621f5,
-       0xf40464b6,
-       0x5bcb6a11,
-       0x0076bbe0,
+       0x0aa521f5,
+       0xf50464b6,
+       0xc700d011,
+       0x76bbe0c5,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0xf550fc04,
+       0xb60a4a21,
+       0x11f50464,
+       0x57f000ad,
+       0x0076bb01,
        0xf90465b6,
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
        0x21f550fc,
-       0x64b607db,
-       0x025bb904,
-       0x0ef474bd,
-/* 0x0abd: i2c_recv_not_rd08 */
-       0x01d6b043,
-       0xf03d1bf4,
-       0x21f50057,
-       0x11f40943,
-       0xe0c5c733,
-       0x08e821f5,
-       0xf02911f4,
-       0x21f50057,
-       0x11f40943,
-       0xe0b5c71f,
-       0x08e821f5,
-       0xf51511f4,
-       0xbd07db21,
-       0x08c5c774,
-       0xf4091bf4,
-       0x0ef40232,
-/* 0x0afd: i2c_recv_not_wr08 */
-/* 0x0afd: i2c_recv_done */
-       0xf8cec703,
-       0x09a821f5,
-       0xd0fce0fc,
-       0xb90a12f4,
-       0x21f5027c,
-/* 0x0b12: i2c_recv_exit */
-       0x00f80342,
-/* 0x0b14: i2c_init */
-/* 0x0b16: test_recv */
-       0x17f100f8,
-       0x14b605d8,
-       0x0011cf06,
-       0xf10110b6,
-       0xb605d807,
-       0x01d00604,
-       0xf104bd00,
-       0xf1d900e7,
-       0xf5134fe3,
-       0xf8026221,
-/* 0x0b3d: test_init */
-       0x00e7f100,
-       0x6221f508,
-/* 0x0b47: idle_recv */
-       0xf800f802,
-/* 0x0b49: idle */
-       0x0031f400,
-       0x05d417f1,
+       0x64b60aa5,
+       0x8a11f504,
+       0x0076bb00,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b609f8,
+       0x6a11f404,
+       0xbbe05bcb,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x093d21f5,
+       0xb90464b6,
+       0x74bd025b,
+/* 0x0c1f: i2c_recv_not_rd08 */
+       0xb0430ef4,
+       0x1bf401d6,
+       0x0057f03d,
+       0x0aa521f5,
+       0xc73311f4,
+       0x21f5e0c5,
+       0x11f40a4a,
+       0x0057f029,
+       0x0aa521f5,
+       0xc71f11f4,
+       0x21f5e0b5,
+       0x11f40a4a,
+       0x3d21f515,
+       0xc774bd09,
+       0x1bf408c5,
+       0x0232f409,
+/* 0x0c5f: i2c_recv_not_wr08 */
+/* 0x0c5f: i2c_recv_done */
+       0xc7030ef4,
+       0x21f5f8ce,
+       0xe0fc0b0a,
+       0x12f4d0fc,
+       0x027cb90a,
+       0x034221f5,
+/* 0x0c74: i2c_recv_exit */
+/* 0x0c76: i2c_init */
+       0x00f800f8,
+/* 0x0c78: test_recv */
+       0x05d817f1,
        0xcf0614b6,
        0x10b60011,
-       0xd407f101,
+       0xd807f101,
        0x0604b605,
        0xbd0001d0,
-/* 0x0b65: idle_loop */
-       0x5817f004,
-/* 0x0b6b: idle_proc */
-/* 0x0b6b: idle_proc_exec */
-       0xf90232f4,
-       0x021eb910,
-       0x034b21f5,
-       0x11f410fc,
-       0x0231f409,
-/* 0x0b7f: idle_proc_next */
-       0xb6ef0ef4,
-       0x1fb85810,
-       0xe61bf406,
-       0xf4dd02f4,
-       0x0ef40028,
-       0x000000bb,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+       0x00e7f104,
+       0x4fe3f1d9,
+       0x6221f513,
+/* 0x0c9f: test_init */
+       0xf100f802,
+       0xf50800e7,
+       0xf8026221,
+/* 0x0ca9: idle_recv */
+/* 0x0cab: idle */
+       0xf400f800,
+       0x17f10031,
+       0x14b605d4,
+       0x0011cf06,
+       0xf10110b6,
+       0xb605d407,
+       0x01d00604,
+/* 0x0cc7: idle_loop */
+       0xf004bd00,
+       0x32f45817,
+/* 0x0ccd: idle_proc */
+/* 0x0ccd: idle_proc_exec */
+       0xb910f902,
+       0x21f5021e,
+       0x10fc034b,
+       0xf40911f4,
+       0x0ef40231,
+/* 0x0ce1: idle_proc_next */
+       0x5810b6ef,
+       0xf4061fb8,
+       0x02f4e61b,
+       0x0028f4dd,
+       0x00bb0ef4,
        0x00000000,
        0x00000000,
        0x00000000,
index ca30fa4011b55907bb1f5d7b207b3291689f55e2..90221d973f84874f72d5f56a60bb06748844feed 100644 (file)
@@ -46,8 +46,8 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x584d454d,
-       0x0000074b,
-       0x0000073d,
+       0x0000075e,
+       0x00000750,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -68,8 +68,8 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x46524550,
-       0x0000074f,
-       0x0000074d,
+       0x00000762,
+       0x00000760,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -90,8 +90,8 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x5f433249,
-       0x00000b7f,
-       0x00000a22,
+       0x00000b92,
+       0x00000a35,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -112,8 +112,8 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x54534554,
-       0x00000ba8,
-       0x00000b81,
+       0x00000bbb,
+       0x00000b94,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -134,8 +134,8 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x454c4449,
-       0x00000bb4,
-       0x00000bb2,
+       0x00000bc7,
+       0x00000bc5,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -246,13 +246,15 @@ uint32_t nvc0_pwr_data[] = {
        0x00010006,
        0x00000000,
        0x00000663,
-/* 0x03b8: memx_func_tail */
-/* 0x03b8: memx_ts_start */
+       0x00000007,
        0x00000000,
-/* 0x03bc: memx_ts_end */
+       0x000006e9,
+/* 0x03c4: memx_func_tail */
+/* 0x03c4: memx_ts_start */
        0x00000000,
-/* 0x03c0: memx_data_head */
+/* 0x03c8: memx_ts_end */
        0x00000000,
+/* 0x03cc: memx_data_head */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -764,8 +766,75 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0bc0: memx_data_tail */
-/* 0x0bc0: i2c_scl_map */
+       0x00000000,
+/* 0x0bcc: memx_data_tail */
+/* 0x0bcc: memx_train_head */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0ccc: memx_train_tail */
+/* 0x0ccc: i2c_scl_map */
        0x00001000,
        0x00004000,
        0x00010000,
@@ -776,7 +845,7 @@ uint32_t nvc0_pwr_data[] = {
        0x01000000,
        0x04000000,
        0x10000000,
-/* 0x0be8: i2c_sda_map */
+/* 0x0cf4: i2c_sda_map */
        0x00002000,
        0x00008000,
        0x00020000,
@@ -787,7 +856,7 @@ uint32_t nvc0_pwr_data[] = {
        0x02000000,
        0x08000000,
        0x20000000,
-/* 0x0c10: i2c_ctrl */
+/* 0x0d1c: i2c_ctrl */
        0x0000e138,
        0x0000e150,
        0x0000e168,
@@ -845,9 +914,6 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
 };
 
 uint32_t nvc0_pwr_code[] = {
@@ -1272,10 +1338,10 @@ uint32_t nvc0_pwr_code[] = {
        0xcf0664b6,
        0x06800066,
 /* 0x05db: memx_func_leave */
-       0xf000f8ee,
+       0xf000f8f1,
        0x64b62c67,
        0x0066cf06,
-       0xf0ef0680,
+       0xf0f20680,
        0x07f10467,
        0x04b607e4,
        0x0006d006,
@@ -1350,382 +1416,450 @@ uint32_t nvc0_pwr_code[] = {
        0x1e9800f8,
        0x0410b600,
        0xf87f21f4,
-/* 0x06e9: memx_exec */
-       0xf9e0f900,
-       0x02c1b9d0,
-/* 0x06f3: memx_exec_next */
-       0x9802b2b9,
-       0x10b60013,
-       0xf034e704,
-       0xe033e701,
-       0x0132b601,
-       0x980c30f0,
-       0x55f9de35,
-       0xf40612b8,
-       0x0b98e41e,
-       0xef0c98ee,
-       0xf102cbbb,
-       0xb607c4b7,
-       0xbbcf06b4,
-       0xfcd0fc00,
-       0x4221f5e0,
-/* 0x072f: memx_info */
-       0xf100f803,
-       0xf103c0c7,
-       0xf50800b7,
+/* 0x06e9: memx_func_train */
+/* 0x06eb: memx_exec */
+       0xf900f800,
+       0xb9d0f9e0,
+       0xb2b902c1,
+/* 0x06f5: memx_exec_next */
+       0x00139802,
+       0xe70410b6,
+       0xe701f034,
+       0xb601e033,
+       0x30f00132,
+       0xde35980c,
+       0x12b855f9,
+       0xe41ef406,
+       0x98f10b98,
+       0xcbbbf20c,
+       0xc4b7f102,
+       0x06b4b607,
+       0xfc00bbcf,
+       0xf5e0fcd0,
        0xf8034221,
-/* 0x073d: memx_recv */
-       0x01d6b000,
-       0xb0a90bf4,
-       0x0bf400d6,
-/* 0x074b: memx_init */
-       0xf800f8e9,
-/* 0x074d: perf_recv */
-/* 0x074f: perf_init */
-       0xf800f800,
-/* 0x0751: i2c_drive_scl */
-       0x0036b000,
-       0xf1110bf4,
-       0xb607e007,
-       0x01d00604,
-       0xf804bd00,
-/* 0x0765: i2c_drive_scl_lo */
-       0xe407f100,
-       0x0604b607,
-       0xbd0001d0,
-/* 0x0773: i2c_drive_sda */
-       0xb000f804,
-       0x0bf40036,
-       0xe007f111,
-       0x0604b607,
-       0xbd0002d0,
-/* 0x0787: i2c_drive_sda_lo */
-       0xf100f804,
-       0xb607e407,
-       0x02d00604,
-       0xf804bd00,
-/* 0x0795: i2c_sense_scl */
-       0x0132f400,
-       0x07c437f1,
-       0xcf0634b6,
-       0x31fd0033,
-       0x060bf404,
-/* 0x07ab: i2c_sense_scl_done */
-       0xf80131f4,
-/* 0x07ad: i2c_sense_sda */
-       0x0132f400,
-       0x07c437f1,
-       0xcf0634b6,
-       0x32fd0033,
-       0x060bf404,
-/* 0x07c3: i2c_sense_sda_done */
-       0xf80131f4,
-/* 0x07c5: i2c_raise_scl */
-       0xf140f900,
-       0xf0089847,
-       0x21f50137,
-/* 0x07d2: i2c_raise_scl_wait */
-       0xe7f10751,
-       0x21f403e8,
-       0x9521f57f,
-       0x0901f407,
-       0xf40142b6,
-/* 0x07e6: i2c_raise_scl_done */
-       0x40fcef1b,
-/* 0x07ea: i2c_start */
-       0x21f500f8,
-       0x11f40795,
-       0xad21f50d,
-       0x0611f407,
-/* 0x07fb: i2c_start_rep */
-       0xf0300ef4,
-       0x21f50037,
-       0x37f00751,
-       0x7321f501,
-       0x0076bb07,
-       0xf90465b6,
-       0x04659450,
-       0xbd0256bb,
-       0x0475fd50,
-       0x21f550fc,
-       0x64b607c5,
-       0x1f11f404,
-/* 0x0828: i2c_start_send */
-       0xf50037f0,
-       0xf1077321,
-       0xf41388e7,
-       0x37f07f21,
-       0x5121f500,
-       0x88e7f107,
-       0x7f21f413,
-/* 0x0844: i2c_start_out */
-/* 0x0846: i2c_stop */
-       0x37f000f8,
-       0x5121f500,
-       0x0037f007,
-       0x077321f5,
-       0x03e8e7f1,
-       0xf07f21f4,
-       0x21f50137,
-       0xe7f10751,
-       0x21f41388,
-       0x0137f07f,
-       0x077321f5,
-       0x1388e7f1,
-       0xf87f21f4,
-/* 0x0879: i2c_bitw */
-       0x7321f500,
+/* 0x0731: memx_info */
+       0x01c67000,
+/* 0x0737: memx_info_data */
+       0xf10e0bf4,
+       0xf103ccc7,
+       0xf40800b7,
+/* 0x0742: memx_info_train */
+       0xc7f10b0e,
+       0xb7f10bcc,
+/* 0x074a: memx_info_send */
+       0x21f50100,
+       0x00f80342,
+/* 0x0750: memx_recv */
+       0xf401d6b0,
+       0xd6b0980b,
+       0xd80bf400,
+/* 0x075e: memx_init */
+       0x00f800f8,
+/* 0x0760: perf_recv */
+/* 0x0762: perf_init */
+       0x00f800f8,
+/* 0x0764: i2c_drive_scl */
+       0xf40036b0,
+       0x07f1110b,
+       0x04b607e0,
+       0x0001d006,
+       0x00f804bd,
+/* 0x0778: i2c_drive_scl_lo */
+       0x07e407f1,
+       0xd00604b6,
+       0x04bd0001,
+/* 0x0786: i2c_drive_sda */
+       0x36b000f8,
+       0x110bf400,
+       0x07e007f1,
+       0xd00604b6,
+       0x04bd0002,
+/* 0x079a: i2c_drive_sda_lo */
+       0x07f100f8,
+       0x04b607e4,
+       0x0002d006,
+       0x00f804bd,
+/* 0x07a8: i2c_sense_scl */
+       0xf10132f4,
+       0xb607c437,
+       0x33cf0634,
+       0x0431fd00,
+       0xf4060bf4,
+/* 0x07be: i2c_sense_scl_done */
+       0x00f80131,
+/* 0x07c0: i2c_sense_sda */
+       0xf10132f4,
+       0xb607c437,
+       0x33cf0634,
+       0x0432fd00,
+       0xf4060bf4,
+/* 0x07d6: i2c_sense_sda_done */
+       0x00f80131,
+/* 0x07d8: i2c_raise_scl */
+       0x47f140f9,
+       0x37f00898,
+       0x6421f501,
+/* 0x07e5: i2c_raise_scl_wait */
        0xe8e7f107,
        0x7f21f403,
+       0x07a821f5,
+       0xb60901f4,
+       0x1bf40142,
+/* 0x07f9: i2c_raise_scl_done */
+       0xf840fcef,
+/* 0x07fd: i2c_start */
+       0xa821f500,
+       0x0d11f407,
+       0x07c021f5,
+       0xf40611f4,
+/* 0x080e: i2c_start_rep */
+       0x37f0300e,
+       0x6421f500,
+       0x0137f007,
+       0x078621f5,
        0xb60076bb,
        0x50f90465,
        0xbb046594,
        0x50bd0256,
        0xfc0475fd,
-       0xc521f550,
+       0xd821f550,
        0x0464b607,
-       0xf11811f4,
-       0xf41388e7,
+/* 0x083b: i2c_start_send */
+       0xf01f11f4,
+       0x21f50037,
+       0xe7f10786,
+       0x21f41388,
+       0x0037f07f,
+       0x076421f5,
+       0x1388e7f1,
+/* 0x0857: i2c_start_out */
+       0xf87f21f4,
+/* 0x0859: i2c_stop */
+       0x0037f000,
+       0x076421f5,
+       0xf50037f0,
+       0xf1078621,
+       0xf403e8e7,
        0x37f07f21,
-       0x5121f500,
+       0x6421f501,
        0x88e7f107,
        0x7f21f413,
-/* 0x08b8: i2c_bitw_out */
-/* 0x08ba: i2c_bitr */
-       0x37f000f8,
-       0x7321f501,
-       0xe8e7f107,
-       0x7f21f403,
-       0xb60076bb,
-       0x50f90465,
-       0xbb046594,
-       0x50bd0256,
-       0xfc0475fd,
-       0xc521f550,
-       0x0464b607,
-       0xf51b11f4,
-       0xf007ad21,
-       0x21f50037,
-       0xe7f10751,
+       0xf50137f0,
+       0xf1078621,
+       0xf41388e7,
+       0x00f87f21,
+/* 0x088c: i2c_bitw */
+       0x078621f5,
+       0x03e8e7f1,
+       0xbb7f21f4,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x07d821f5,
+       0xf40464b6,
+       0xe7f11811,
        0x21f41388,
-       0x013cf07f,
-/* 0x08ff: i2c_bitr_done */
-       0xf80131f4,
-/* 0x0901: i2c_get_byte */
-       0x0057f000,
-/* 0x0907: i2c_get_byte_next */
-       0xb60847f0,
-       0x76bb0154,
-       0x0465b600,
-       0x659450f9,
-       0x0256bb04,
-       0x75fd50bd,
-       0xf550fc04,
-       0xb608ba21,
-       0x11f40464,
-       0x0553fd2b,
-       0xf40142b6,
-       0x37f0d81b,
+       0x0037f07f,
+       0x076421f5,
+       0x1388e7f1,
+/* 0x08cb: i2c_bitw_out */
+       0xf87f21f4,
+/* 0x08cd: i2c_bitr */
+       0x0137f000,
+       0x078621f5,
+       0x03e8e7f1,
+       0xbb7f21f4,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x07d821f5,
+       0xf40464b6,
+       0x21f51b11,
+       0x37f007c0,
+       0x6421f500,
+       0x88e7f107,
+       0x7f21f413,
+       0xf4013cf0,
+/* 0x0912: i2c_bitr_done */
+       0x00f80131,
+/* 0x0914: i2c_get_byte */
+       0xf00057f0,
+/* 0x091a: i2c_get_byte_next */
+       0x54b60847,
        0x0076bb01,
        0xf90465b6,
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
        0x21f550fc,
-       0x64b60879,
-/* 0x0951: i2c_get_byte_done */
-/* 0x0953: i2c_put_byte */
-       0xf000f804,
-/* 0x0956: i2c_put_byte_next */
-       0x42b60847,
-       0x3854ff01,
+       0x64b608cd,
+       0x2b11f404,
+       0xb60553fd,
+       0x1bf40142,
+       0x0137f0d8,
        0xb60076bb,
        0x50f90465,
        0xbb046594,
        0x50bd0256,
        0xfc0475fd,
-       0x7921f550,
+       0x8c21f550,
        0x0464b608,
-       0xb03411f4,
-       0x1bf40046,
-       0x0076bbd8,
+/* 0x0964: i2c_get_byte_done */
+/* 0x0966: i2c_put_byte */
+       0x47f000f8,
+/* 0x0969: i2c_put_byte_next */
+       0x0142b608,
+       0xbb3854ff,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x088c21f5,
+       0xf40464b6,
+       0x46b03411,
+       0xd81bf400,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0xcd21f550,
+       0x0464b608,
+       0xbb0f11f4,
+       0x36b00076,
+       0x061bf401,
+/* 0x09bf: i2c_put_byte_done */
+       0xf80132f4,
+/* 0x09c1: i2c_addr */
+       0x0076bb00,
        0xf90465b6,
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
        0x21f550fc,
-       0x64b608ba,
-       0x0f11f404,
-       0xb00076bb,
-       0x1bf40136,
-       0x0132f406,
-/* 0x09ac: i2c_put_byte_done */
-/* 0x09ae: i2c_addr */
-       0x76bb00f8,
+       0x64b607fd,
+       0x2911f404,
+       0x012ec3e7,
+       0xfd0134b6,
+       0x76bb0553,
        0x0465b600,
        0x659450f9,
        0x0256bb04,
        0x75fd50bd,
        0xf550fc04,
-       0xb607ea21,
-       0x11f40464,
-       0x2ec3e729,
-       0x0134b601,
-       0xbb0553fd,
+       0xb6096621,
+/* 0x0a06: i2c_addr_done */
+       0x00f80464,
+/* 0x0a08: i2c_acquire_addr */
+       0xb6f8cec7,
+       0xe0b702e4,
+       0xee980d1c,
+/* 0x0a17: i2c_acquire */
+       0xf500f800,
+       0xf40a0821,
+       0xd9f00421,
+       0x3f21f403,
+/* 0x0a26: i2c_release */
+       0x21f500f8,
+       0x21f40a08,
+       0x03daf004,
+       0xf83f21f4,
+/* 0x0a35: i2c_recv */
+       0x0132f400,
+       0xb6f8c1c7,
+       0x16b00214,
+       0x3a1ff528,
+       0xf413a001,
+       0x0032980c,
+       0x0ccc13a0,
+       0xf4003198,
+       0xd0f90231,
+       0xd0f9e0f9,
+       0x000067f1,
+       0x100063f1,
+       0xbb016792,
        0x65b60076,
        0x9450f904,
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x095321f5,
-/* 0x09f3: i2c_addr_done */
-       0xf80464b6,
-/* 0x09f5: i2c_acquire_addr */
-       0xf8cec700,
-       0xb702e4b6,
-       0x980c10e0,
-       0x00f800ee,
-/* 0x0a04: i2c_acquire */
-       0x09f521f5,
-       0xf00421f4,
-       0x21f403d9,
-/* 0x0a13: i2c_release */
-       0xf500f83f,
-       0xf409f521,
-       0xdaf00421,
-       0x3f21f403,
-/* 0x0a22: i2c_recv */
-       0x32f400f8,
-       0xf8c1c701,
-       0xb00214b6,
-       0x1ff52816,
-       0x13a0013a,
-       0x32980be8,
-       0xc013a000,
-       0x0031980b,
-       0xf90231f4,
-       0xf9e0f9d0,
-       0x0067f1d0,
-       0x0063f100,
-       0x01679210,
-       0xb60076bb,
-       0x50f90465,
-       0xbb046594,
-       0x50bd0256,
-       0xfc0475fd,
-       0x0421f550,
-       0x0464b60a,
-       0xd6b0d0fc,
-       0xb31bf500,
-       0x0057f000,
-       0xb60076bb,
-       0x50f90465,
-       0xbb046594,
-       0x50bd0256,
-       0xfc0475fd,
-       0xae21f550,
-       0x0464b609,
-       0x00d011f5,
-       0xbbe0c5c7,
+       0x0a1721f5,
+       0xfc0464b6,
+       0x00d6b0d0,
+       0x00b31bf5,
+       0xbb0057f0,
        0x65b60076,
        0x9450f904,
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x095321f5,
+       0x09c121f5,
        0xf50464b6,
-       0xf000ad11,
-       0x76bb0157,
+       0xc700d011,
+       0x76bbe0c5,
        0x0465b600,
        0x659450f9,
        0x0256bb04,
        0x75fd50bd,
        0xf550fc04,
-       0xb609ae21,
+       0xb6096621,
        0x11f50464,
-       0x76bb008a,
-       0x0465b600,
-       0x659450f9,
-       0x0256bb04,
-       0x75fd50bd,
-       0xf550fc04,
-       0xb6090121,
-       0x11f40464,
-       0xe05bcb6a,
-       0xb60076bb,
-       0x50f90465,
-       0xbb046594,
-       0x50bd0256,
-       0xfc0475fd,
-       0x4621f550,
-       0x0464b608,
-       0xbd025bb9,
-       0x430ef474,
-/* 0x0b28: i2c_recv_not_rd08 */
-       0xf401d6b0,
-       0x57f03d1b,
-       0xae21f500,
-       0x3311f409,
-       0xf5e0c5c7,
-       0xf4095321,
-       0x57f02911,
-       0xae21f500,
-       0x1f11f409,
-       0xf5e0b5c7,
-       0xf4095321,
-       0x21f51511,
-       0x74bd0846,
-       0xf408c5c7,
-       0x32f4091b,
-       0x030ef402,
-/* 0x0b68: i2c_recv_not_wr08 */
-/* 0x0b68: i2c_recv_done */
-       0xf5f8cec7,
-       0xfc0a1321,
-       0xf4d0fce0,
-       0x7cb90a12,
-       0x4221f502,
-/* 0x0b7d: i2c_recv_exit */
-/* 0x0b7f: i2c_init */
-       0xf800f803,
-/* 0x0b81: test_recv */
-       0xd817f100,
-       0x0614b605,
-       0xb60011cf,
-       0x07f10110,
-       0x04b605d8,
-       0x0001d006,
-       0xe7f104bd,
-       0xe3f1d900,
-       0x21f5134f,
-       0x00f80262,
-/* 0x0ba8: test_init */
-       0x0800e7f1,
-       0x026221f5,
-/* 0x0bb2: idle_recv */
+       0x57f000ad,
+       0x0076bb01,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b609c1,
+       0x8a11f504,
+       0x0076bb00,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b60914,
+       0x6a11f404,
+       0xbbe05bcb,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x085921f5,
+       0xb90464b6,
+       0x74bd025b,
+/* 0x0b3b: i2c_recv_not_rd08 */
+       0xb0430ef4,
+       0x1bf401d6,
+       0x0057f03d,
+       0x09c121f5,
+       0xc73311f4,
+       0x21f5e0c5,
+       0x11f40966,
+       0x0057f029,
+       0x09c121f5,
+       0xc71f11f4,
+       0x21f5e0b5,
+       0x11f40966,
+       0x5921f515,
+       0xc774bd08,
+       0x1bf408c5,
+       0x0232f409,
+/* 0x0b7b: i2c_recv_not_wr08 */
+/* 0x0b7b: i2c_recv_done */
+       0xc7030ef4,
+       0x21f5f8ce,
+       0xe0fc0a26,
+       0x12f4d0fc,
+       0x027cb90a,
+       0x034221f5,
+/* 0x0b90: i2c_recv_exit */
+/* 0x0b92: i2c_init */
        0x00f800f8,
-/* 0x0bb4: idle */
-       0xf10031f4,
-       0xb605d417,
-       0x11cf0614,
-       0x0110b600,
-       0x05d407f1,
-       0xd00604b6,
-       0x04bd0001,
-/* 0x0bd0: idle_loop */
-       0xf45817f0,
-/* 0x0bd6: idle_proc */
-/* 0x0bd6: idle_proc_exec */
-       0x10f90232,
-       0xf5021eb9,
-       0xfc034b21,
-       0x0911f410,
-       0xf40231f4,
-/* 0x0bea: idle_proc_next */
-       0x10b6ef0e,
-       0x061fb858,
-       0xf4e61bf4,
-       0x28f4dd02,
-       0xbb0ef400,
+/* 0x0b94: test_recv */
+       0x05d817f1,
+       0xcf0614b6,
+       0x10b60011,
+       0xd807f101,
+       0x0604b605,
+       0xbd0001d0,
+       0x00e7f104,
+       0x4fe3f1d9,
+       0x6221f513,
+/* 0x0bbb: test_init */
+       0xf100f802,
+       0xf50800e7,
+       0xf8026221,
+/* 0x0bc5: idle_recv */
+/* 0x0bc7: idle */
+       0xf400f800,
+       0x17f10031,
+       0x14b605d4,
+       0x0011cf06,
+       0xf10110b6,
+       0xb605d407,
+       0x01d00604,
+/* 0x0be3: idle_loop */
+       0xf004bd00,
+       0x32f45817,
+/* 0x0be9: idle_proc */
+/* 0x0be9: idle_proc_exec */
+       0xb910f902,
+       0x21f5021e,
+       0x10fc034b,
+       0xf40911f4,
+       0x0ef40231,
+/* 0x0bfd: idle_proc_next */
+       0x5810b6ef,
+       0xf4061fb8,
+       0x02f4e61b,
+       0x0028f4dd,
+       0x00bb0ef4,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
        0x00000000,
 };
index 12d86f72ad105a191f152d38c1f0b4363c856ba1..7e16aab44d855041dc00e974fced69f48a4aba56 100644 (file)
@@ -46,8 +46,8 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x584d454d,
-       0x00000678,
-       0x0000066a,
+       0x0000068b,
+       0x0000067d,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -68,8 +68,8 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x46524550,
-       0x0000067c,
-       0x0000067a,
+       0x0000068f,
+       0x0000068d,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -90,8 +90,8 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x5f433249,
-       0x00000a97,
-       0x0000093a,
+       0x00000aaa,
+       0x0000094d,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -112,8 +112,8 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x54534554,
-       0x00000aba,
-       0x00000a99,
+       0x00000acd,
+       0x00000aac,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -134,8 +134,8 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x454c4449,
-       0x00000ac6,
-       0x00000ac4,
+       0x00000ad9,
+       0x00000ad7,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -246,13 +246,15 @@ uint32_t nvd0_pwr_data[] = {
        0x00010006,
        0x00000000,
        0x000005d3,
-/* 0x03b8: memx_func_tail */
-/* 0x03b8: memx_ts_start */
+       0x00000007,
        0x00000000,
-/* 0x03bc: memx_ts_end */
+       0x00000619,
+/* 0x03c4: memx_func_tail */
+/* 0x03c4: memx_ts_start */
        0x00000000,
-/* 0x03c0: memx_data_head */
+/* 0x03c8: memx_ts_end */
        0x00000000,
+/* 0x03cc: memx_data_head */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -764,8 +766,75 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0bc0: memx_data_tail */
-/* 0x0bc0: i2c_scl_map */
+       0x00000000,
+/* 0x0bcc: memx_data_tail */
+/* 0x0bcc: memx_train_head */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0ccc: memx_train_tail */
+/* 0x0ccc: i2c_scl_map */
        0x00000400,
        0x00000800,
        0x00001000,
@@ -776,7 +845,7 @@ uint32_t nvd0_pwr_data[] = {
        0x00020000,
        0x00040000,
        0x00080000,
-/* 0x0be8: i2c_sda_map */
+/* 0x0cf4: i2c_sda_map */
        0x00100000,
        0x00200000,
        0x00400000,
@@ -844,9 +913,6 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
 };
 
 uint32_t nvd0_pwr_code[] = {
@@ -1236,11 +1302,11 @@ uint32_t nvd0_pwr_code[] = {
        0x0bf40464,
        0x2c67f0f6,
        0x800066cf,
-       0x00f8ee06,
+       0x00f8f106,
 /* 0x0554: memx_func_leave */
        0xcf2c67f0,
        0x06800066,
-       0x0467f0ef,
+       0x0467f0f2,
        0x07e407f1,
        0xbd0006d0,
 /* 0x0569: memx_func_leave_wait */
@@ -1292,379 +1358,383 @@ uint32_t nvd0_pwr_code[] = {
        0x1e9800f8,
        0x0410b600,
        0xf86721f4,
-/* 0x0619: memx_exec */
-       0xf9e0f900,
-       0x02c1b9d0,
-/* 0x0623: memx_exec_next */
-       0x9802b2b9,
-       0x10b60013,
-       0xf034e704,
-       0xe033e701,
-       0x0132b601,
-       0x980c30f0,
-       0x55f9de35,
-       0xf40612b8,
-       0x0b98e41e,
-       0xef0c98ee,
-       0xf102cbbb,
-       0xcf07c4b7,
-       0xd0fc00bb,
-       0x21f5e0fc,
-       0x00f802f1,
-/* 0x065c: memx_info */
-       0x03c0c7f1,
-       0x0800b7f1,
+/* 0x0619: memx_func_train */
+/* 0x061b: memx_exec */
+       0xf900f800,
+       0xb9d0f9e0,
+       0xb2b902c1,
+/* 0x0625: memx_exec_next */
+       0x00139802,
+       0xe70410b6,
+       0xe701f034,
+       0xb601e033,
+       0x30f00132,
+       0xde35980c,
+       0x12b855f9,
+       0xe41ef406,
+       0x98f10b98,
+       0xcbbbf20c,
+       0xc4b7f102,
+       0x00bbcf07,
+       0xe0fcd0fc,
        0x02f121f5,
-/* 0x066a: memx_recv */
-       0xd6b000f8,
-       0xac0bf401,
-       0xf400d6b0,
-       0x00f8e90b,
-/* 0x0678: memx_init */
-/* 0x067a: perf_recv */
-       0x00f800f8,
-/* 0x067c: perf_init */
-/* 0x067e: i2c_drive_scl */
-       0x36b000f8,
-       0x0e0bf400,
-       0x07e007f1,
-       0xbd0001d0,
-/* 0x068f: i2c_drive_scl_lo */
-       0xf100f804,
-       0xd007e407,
+/* 0x065e: memx_info */
+       0xc67000f8,
+       0x0e0bf401,
+/* 0x0664: memx_info_data */
+       0x03ccc7f1,
+       0x0800b7f1,
+/* 0x066f: memx_info_train */
+       0xf10b0ef4,
+       0xf10bccc7,
+/* 0x0677: memx_info_send */
+       0xf50100b7,
+       0xf802f121,
+/* 0x067d: memx_recv */
+       0x01d6b000,
+       0xb09b0bf4,
+       0x0bf400d6,
+/* 0x068b: memx_init */
+       0xf800f8d8,
+/* 0x068d: perf_recv */
+/* 0x068f: perf_init */
+       0xf800f800,
+/* 0x0691: i2c_drive_scl */
+       0x0036b000,
+       0xf10e0bf4,
+       0xd007e007,
        0x04bd0001,
-/* 0x069a: i2c_drive_sda */
-       0x36b000f8,
-       0x0e0bf400,
-       0x07e007f1,
-       0xbd0002d0,
-/* 0x06ab: i2c_drive_sda_lo */
-       0xf100f804,
-       0xd007e407,
+/* 0x06a2: i2c_drive_scl_lo */
+       0x07f100f8,
+       0x01d007e4,
+       0xf804bd00,
+/* 0x06ad: i2c_drive_sda */
+       0x0036b000,
+       0xf10e0bf4,
+       0xd007e007,
        0x04bd0002,
-/* 0x06b6: i2c_sense_scl */
+/* 0x06be: i2c_drive_sda_lo */
+       0x07f100f8,
+       0x02d007e4,
+       0xf804bd00,
+/* 0x06c9: i2c_sense_scl */
+       0x0132f400,
+       0x07c437f1,
+       0xfd0033cf,
+       0x0bf40431,
+       0x0131f406,
+/* 0x06dc: i2c_sense_scl_done */
+/* 0x06de: i2c_sense_sda */
        0x32f400f8,
        0xc437f101,
        0x0033cf07,
-       0xf40431fd,
+       0xf40432fd,
        0x31f4060b,
-/* 0x06c9: i2c_sense_scl_done */
-/* 0x06cb: i2c_sense_sda */
-       0xf400f801,
-       0x37f10132,
-       0x33cf07c4,
-       0x0432fd00,
-       0xf4060bf4,
-/* 0x06de: i2c_sense_sda_done */
-       0x00f80131,
-/* 0x06e0: i2c_raise_scl */
-       0x47f140f9,
-       0x37f00898,
-       0x7e21f501,
-/* 0x06ed: i2c_raise_scl_wait */
-       0xe8e7f106,
-       0x6721f403,
-       0x06b621f5,
-       0xb60901f4,
-       0x1bf40142,
-/* 0x0701: i2c_raise_scl_done */
-       0xf840fcef,
-/* 0x0705: i2c_start */
-       0xb621f500,
-       0x0d11f406,
-       0x06cb21f5,
-       0xf40611f4,
-/* 0x0716: i2c_start_rep */
-       0x37f0300e,
-       0x7e21f500,
-       0x0137f006,
-       0x069a21f5,
-       0xb60076bb,
-       0x50f90465,
-       0xbb046594,
-       0x50bd0256,
-       0xfc0475fd,
-       0xe021f550,
-       0x0464b606,
-/* 0x0743: i2c_start_send */
-       0xf01f11f4,
-       0x21f50037,
-       0xe7f1069a,
-       0x21f41388,
-       0x0037f067,
-       0x067e21f5,
-       0x1388e7f1,
-/* 0x075f: i2c_start_out */
-       0xf86721f4,
-/* 0x0761: i2c_stop */
-       0x0037f000,
-       0x067e21f5,
-       0xf50037f0,
-       0xf1069a21,
-       0xf403e8e7,
-       0x37f06721,
-       0x7e21f501,
-       0x88e7f106,
-       0x6721f413,
-       0xf50137f0,
-       0xf1069a21,
-       0xf41388e7,
-       0x00f86721,
-/* 0x0794: i2c_bitw */
-       0x069a21f5,
+/* 0x06f1: i2c_sense_sda_done */
+/* 0x06f3: i2c_raise_scl */
+       0xf900f801,
+       0x9847f140,
+       0x0137f008,
+       0x069121f5,
+/* 0x0700: i2c_raise_scl_wait */
        0x03e8e7f1,
-       0xbb6721f4,
-       0x65b60076,
-       0x9450f904,
-       0x56bb0465,
-       0xfd50bd02,
-       0x50fc0475,
-       0x06e021f5,
-       0xf40464b6,
-       0xe7f11811,
-       0x21f41388,
-       0x0037f067,
-       0x067e21f5,
-       0x1388e7f1,
-/* 0x07d3: i2c_bitw_out */
-       0xf86721f4,
-/* 0x07d5: i2c_bitr */
-       0x0137f000,
-       0x069a21f5,
-       0x03e8e7f1,
-       0xbb6721f4,
+       0xf56721f4,
+       0xf406c921,
+       0x42b60901,
+       0xef1bf401,
+/* 0x0714: i2c_raise_scl_done */
+       0x00f840fc,
+/* 0x0718: i2c_start */
+       0x06c921f5,
+       0xf50d11f4,
+       0xf406de21,
+       0x0ef40611,
+/* 0x0729: i2c_start_rep */
+       0x0037f030,
+       0x069121f5,
+       0xf50137f0,
+       0xbb06ad21,
        0x65b60076,
        0x9450f904,
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x06e021f5,
+       0x06f321f5,
        0xf40464b6,
-       0x21f51b11,
-       0x37f006cb,
-       0x7e21f500,
+/* 0x0756: i2c_start_send */
+       0x37f01f11,
+       0xad21f500,
        0x88e7f106,
        0x6721f413,
-       0xf4013cf0,
-/* 0x081a: i2c_bitr_done */
-       0x00f80131,
-/* 0x081c: i2c_get_byte */
-       0xf00057f0,
-/* 0x0822: i2c_get_byte_next */
-       0x54b60847,
-       0x0076bb01,
-       0xf90465b6,
-       0x04659450,
-       0xbd0256bb,
-       0x0475fd50,
-       0x21f550fc,
-       0x64b607d5,
-       0x2b11f404,
-       0xb60553fd,
-       0x1bf40142,
-       0x0137f0d8,
+       0xf50037f0,
+       0xf1069121,
+       0xf41388e7,
+/* 0x0772: i2c_start_out */
+       0x00f86721,
+/* 0x0774: i2c_stop */
+       0xf50037f0,
+       0xf0069121,
+       0x21f50037,
+       0xe7f106ad,
+       0x21f403e8,
+       0x0137f067,
+       0x069121f5,
+       0x1388e7f1,
+       0xf06721f4,
+       0x21f50137,
+       0xe7f106ad,
+       0x21f41388,
+/* 0x07a7: i2c_bitw */
+       0xf500f867,
+       0xf106ad21,
+       0xf403e8e7,
+       0x76bb6721,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0xf550fc04,
+       0xb606f321,
+       0x11f40464,
+       0x88e7f118,
+       0x6721f413,
+       0xf50037f0,
+       0xf1069121,
+       0xf41388e7,
+/* 0x07e6: i2c_bitw_out */
+       0x00f86721,
+/* 0x07e8: i2c_bitr */
+       0xf50137f0,
+       0xf106ad21,
+       0xf403e8e7,
+       0x76bb6721,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0xf550fc04,
+       0xb606f321,
+       0x11f40464,
+       0xde21f51b,
+       0x0037f006,
+       0x069121f5,
+       0x1388e7f1,
+       0xf06721f4,
+       0x31f4013c,
+/* 0x082d: i2c_bitr_done */
+/* 0x082f: i2c_get_byte */
+       0xf000f801,
+       0x47f00057,
+/* 0x0835: i2c_get_byte_next */
+       0x0154b608,
        0xb60076bb,
        0x50f90465,
        0xbb046594,
        0x50bd0256,
        0xfc0475fd,
-       0x9421f550,
+       0xe821f550,
        0x0464b607,
-/* 0x086c: i2c_get_byte_done */
-/* 0x086e: i2c_put_byte */
-       0x47f000f8,
-/* 0x0871: i2c_put_byte_next */
-       0x0142b608,
-       0xbb3854ff,
+       0xfd2b11f4,
+       0x42b60553,
+       0xd81bf401,
+       0xbb0137f0,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x07a721f5,
+/* 0x087f: i2c_get_byte_done */
+       0xf80464b6,
+/* 0x0881: i2c_put_byte */
+       0x0847f000,
+/* 0x0884: i2c_put_byte_next */
+       0xff0142b6,
+       0x76bb3854,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0xf550fc04,
+       0xb607a721,
+       0x11f40464,
+       0x0046b034,
+       0xbbd81bf4,
        0x65b60076,
        0x9450f904,
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x079421f5,
+       0x07e821f5,
        0xf40464b6,
-       0x46b03411,
-       0xd81bf400,
+       0x76bb0f11,
+       0x0136b000,
+       0xf4061bf4,
+/* 0x08da: i2c_put_byte_done */
+       0x00f80132,
+/* 0x08dc: i2c_addr */
        0xb60076bb,
        0x50f90465,
        0xbb046594,
        0x50bd0256,
        0xfc0475fd,
-       0xd521f550,
+       0x1821f550,
        0x0464b607,
-       0xbb0f11f4,
-       0x36b00076,
-       0x061bf401,
-/* 0x08c7: i2c_put_byte_done */
-       0xf80132f4,
-/* 0x08c9: i2c_addr */
-       0x0076bb00,
+       0xe72911f4,
+       0xb6012ec3,
+       0x53fd0134,
+       0x0076bb05,
        0xf90465b6,
        0x04659450,
        0xbd0256bb,
        0x0475fd50,
        0x21f550fc,
-       0x64b60705,
-       0x2911f404,
-       0x012ec3e7,
-       0xfd0134b6,
-       0x76bb0553,
-       0x0465b600,
-       0x659450f9,
-       0x0256bb04,
-       0x75fd50bd,
-       0xf550fc04,
-       0xb6086e21,
-/* 0x090e: i2c_addr_done */
-       0x00f80464,
-/* 0x0910: i2c_acquire_addr */
-       0xb6f8cec7,
-       0xe0b705e4,
-       0x00f8d014,
-/* 0x091c: i2c_acquire */
-       0x091021f5,
-       0xf00421f4,
-       0x21f403d9,
-/* 0x092b: i2c_release */
-       0xf500f833,
-       0xf4091021,
-       0xdaf00421,
+       0x64b60881,
+/* 0x0921: i2c_addr_done */
+/* 0x0923: i2c_acquire_addr */
+       0xc700f804,
+       0xe4b6f8ce,
+       0x14e0b705,
+/* 0x092f: i2c_acquire */
+       0xf500f8d0,
+       0xf4092321,
+       0xd9f00421,
        0x3321f403,
-/* 0x093a: i2c_recv */
-       0x32f400f8,
-       0xf8c1c701,
-       0xb00214b6,
-       0x1ff52816,
-       0x13a0013a,
-       0x32980be8,
-       0xc013a000,
-       0x0031980b,
-       0xf90231f4,
-       0xf9e0f9d0,
-       0x0067f1d0,
-       0x0063f100,
-       0x01679210,
-       0xb60076bb,
-       0x50f90465,
-       0xbb046594,
-       0x50bd0256,
-       0xfc0475fd,
-       0x1c21f550,
-       0x0464b609,
-       0xd6b0d0fc,
-       0xb31bf500,
-       0x0057f000,
-       0xb60076bb,
-       0x50f90465,
-       0xbb046594,
-       0x50bd0256,
-       0xfc0475fd,
-       0xc921f550,
-       0x0464b608,
-       0x00d011f5,
-       0xbbe0c5c7,
+/* 0x093e: i2c_release */
+       0x21f500f8,
+       0x21f40923,
+       0x03daf004,
+       0xf83321f4,
+/* 0x094d: i2c_recv */
+       0x0132f400,
+       0xb6f8c1c7,
+       0x16b00214,
+       0x3a1ff528,
+       0xf413a001,
+       0x0032980c,
+       0x0ccc13a0,
+       0xf4003198,
+       0xd0f90231,
+       0xd0f9e0f9,
+       0x000067f1,
+       0x100063f1,
+       0xbb016792,
        0x65b60076,
        0x9450f904,
        0x56bb0465,
        0xfd50bd02,
        0x50fc0475,
-       0x086e21f5,
+       0x092f21f5,
+       0xfc0464b6,
+       0x00d6b0d0,
+       0x00b31bf5,
+       0xbb0057f0,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x08dc21f5,
        0xf50464b6,
-       0xf000ad11,
-       0x76bb0157,
+       0xc700d011,
+       0x76bbe0c5,
        0x0465b600,
        0x659450f9,
        0x0256bb04,
        0x75fd50bd,
        0xf550fc04,
-       0xb608c921,
+       0xb6088121,
        0x11f50464,
-       0x76bb008a,
-       0x0465b600,
-       0x659450f9,
-       0x0256bb04,
-       0x75fd50bd,
-       0xf550fc04,
-       0xb6081c21,
-       0x11f40464,
-       0xe05bcb6a,
-       0xb60076bb,
-       0x50f90465,
-       0xbb046594,
-       0x50bd0256,
-       0xfc0475fd,
-       0x6121f550,
-       0x0464b607,
-       0xbd025bb9,
-       0x430ef474,
-/* 0x0a40: i2c_recv_not_rd08 */
-       0xf401d6b0,
-       0x57f03d1b,
-       0xc921f500,
-       0x3311f408,
-       0xf5e0c5c7,
-       0xf4086e21,
-       0x57f02911,
-       0xc921f500,
-       0x1f11f408,
-       0xf5e0b5c7,
-       0xf4086e21,
-       0x21f51511,
-       0x74bd0761,
-       0xf408c5c7,
-       0x32f4091b,
-       0x030ef402,
-/* 0x0a80: i2c_recv_not_wr08 */
-/* 0x0a80: i2c_recv_done */
-       0xf5f8cec7,
-       0xfc092b21,
-       0xf4d0fce0,
-       0x7cb90a12,
-       0xf121f502,
-/* 0x0a95: i2c_recv_exit */
-/* 0x0a97: i2c_init */
+       0x57f000ad,
+       0x0076bb01,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b608dc,
+       0x8a11f504,
+       0x0076bb00,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b6082f,
+       0x6a11f404,
+       0xbbe05bcb,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x077421f5,
+       0xb90464b6,
+       0x74bd025b,
+/* 0x0a53: i2c_recv_not_rd08 */
+       0xb0430ef4,
+       0x1bf401d6,
+       0x0057f03d,
+       0x08dc21f5,
+       0xc73311f4,
+       0x21f5e0c5,
+       0x11f40881,
+       0x0057f029,
+       0x08dc21f5,
+       0xc71f11f4,
+       0x21f5e0b5,
+       0x11f40881,
+       0x7421f515,
+       0xc774bd07,
+       0x1bf408c5,
+       0x0232f409,
+/* 0x0a93: i2c_recv_not_wr08 */
+/* 0x0a93: i2c_recv_done */
+       0xc7030ef4,
+       0x21f5f8ce,
+       0xe0fc093e,
+       0x12f4d0fc,
+       0x027cb90a,
+       0x02f121f5,
+/* 0x0aa8: i2c_recv_exit */
+/* 0x0aaa: i2c_init */
+       0x00f800f8,
+/* 0x0aac: test_recv */
+       0x05d817f1,
+       0xb60011cf,
+       0x07f10110,
+       0x01d005d8,
+       0xf104bd00,
+       0xf1d900e7,
+       0xf5134fe3,
+       0xf8022321,
+/* 0x0acd: test_init */
+       0x00e7f100,
+       0x2321f508,
+/* 0x0ad7: idle_recv */
        0xf800f802,
-/* 0x0a99: test_recv */
-       0xd817f100,
-       0x0011cf05,
-       0xf10110b6,
-       0xd005d807,
-       0x04bd0001,
-       0xd900e7f1,
-       0x134fe3f1,
-       0x022321f5,
-/* 0x0aba: test_init */
-       0xe7f100f8,
-       0x21f50800,
-       0x00f80223,
-/* 0x0ac4: idle_recv */
-/* 0x0ac6: idle */
-       0x31f400f8,
-       0xd417f100,
-       0x0011cf05,
-       0xf10110b6,
-       0xd005d407,
-       0x04bd0001,
-/* 0x0adc: idle_loop */
-       0xf45817f0,
-/* 0x0ae2: idle_proc */
-/* 0x0ae2: idle_proc_exec */
-       0x10f90232,
-       0xf5021eb9,
-       0xfc02fa21,
-       0x0911f410,
-       0xf40231f4,
-/* 0x0af6: idle_proc_next */
-       0x10b6ef0e,
-       0x061fb858,
-       0xf4e61bf4,
-       0x28f4dd02,
-       0xc10ef400,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+/* 0x0ad9: idle */
+       0x0031f400,
+       0x05d417f1,
+       0xb60011cf,
+       0x07f10110,
+       0x01d005d4,
+/* 0x0aef: idle_loop */
+       0xf004bd00,
+       0x32f45817,
+/* 0x0af5: idle_proc */
+/* 0x0af5: idle_proc_exec */
+       0xb910f902,
+       0x21f5021e,
+       0x10fc02fa,
+       0xf40911f4,
+       0x0ef40231,
+/* 0x0b09: idle_proc_next */
+       0x5810b6ef,
+       0xf4061fb8,
+       0x02f4e61b,
+       0x0028f4dd,
+       0x00c10ef4,
        0x00000000,
        0x00000000,
        0x00000000,
index 522e3079f82428e401030c8d34c7124865ec7a3d..c8b06cb77e7241cd50cec944b49adcc0325dd703 100644 (file)
 #define MEMX_MSG_INFO 0
 #define MEMX_MSG_EXEC 1
 
+/* MEMX: info types */
+#define MEMX_INFO_DATA  0
+#define MEMX_INFO_TRAIN 1
+
 /* MEMX: script opcode definitions */
 #define MEMX_ENTER  1
 #define MEMX_LEAVE  2
@@ -25,6 +29,7 @@
 #define MEMX_WAIT   4
 #define MEMX_DELAY  5
 #define MEMX_VBLANK 6
+#define MEMX_TRAIN  7
 
 /* I2C_: message identifiers */
 #define I2C__MSG_RD08 0
index 65eaa2546cad2ce5abbcbc32eea9ac008c8bfd2f..7a9299d7159f5a4fa8d1494f01e0c7c6a4ae7c6f 100644 (file)
@@ -47,7 +47,8 @@ nouveau_memx_init(struct nouveau_pwr *ppwr, struct nouveau_memx **pmemx)
        u32 reply[2];
        int ret;
 
-       ret = ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_INFO, 0, 0);
+       ret = ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_INFO,
+                                       MEMX_INFO_DATA, 0);
        if (ret)
                return ret;
 
@@ -106,7 +107,7 @@ nouveau_memx_wait(struct nouveau_memx *memx,
 {
        nv_debug(memx->ppwr, "R[%06x] & 0x%08x == 0x%08x, %d us\n",
                                addr, mask, data, nsec);
-       memx_cmd(memx, MEMX_WAIT, 4, (u32[]){ addr, ~mask, data, nsec });
+       memx_cmd(memx, MEMX_WAIT, 4, (u32[]){ addr, mask, data, nsec });
        memx_out(memx); /* fuc can't handle multiple */
 }
 
@@ -151,6 +152,38 @@ nouveau_memx_wait_vblank(struct nouveau_memx *memx)
        memx_out(memx); /* fuc can't handle multiple */
 }
 
+void
+nouveau_memx_train(struct nouveau_memx *memx)
+{
+       nv_debug(memx->ppwr, "   MEM TRAIN\n");
+       memx_cmd(memx, MEMX_TRAIN, 0, NULL);
+}
+
+int
+nouveau_memx_train_result(struct nouveau_pwr *ppwr, u32 *res, int rsize)
+{
+       u32 reply[2], base, size, i;
+       int ret;
+
+       ret = ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_INFO,
+                                       MEMX_INFO_TRAIN, 0);
+       if (ret)
+               return ret;
+
+       base = reply[0];
+       size = reply[1] >> 2;
+       if (size > rsize)
+               return -ENOMEM;
+
+       /* read the packet */
+       nv_wr32(ppwr, 0x10a1c0, 0x02000000 | base);
+
+       for (i = 0; i < size; i++)
+               res[i] = nv_rd32(ppwr, 0x10a1c4);
+
+       return 0;
+}
+
 void
 nouveau_memx_block(struct nouveau_memx *memx)
 {
index 32794a999106c3239c851ba59519e3dd3d61e6e9..26ccd8df193f8b5a5c34f5da068c7c9e1fafc61f 100644 (file)
@@ -101,6 +101,41 @@ nouveau_volt_set_id(struct nouveau_volt *volt, u8 id, int condition)
        return ret;
 }
 
+static void nouveau_volt_parse_bios(struct nouveau_bios *bios,
+               struct nouveau_volt *volt)
+{
+       struct nvbios_volt_entry ivid;
+       struct nvbios_volt info;
+       u8  ver, hdr, cnt, len;
+       u16 data;
+       int i;
+
+       data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info);
+       if (data && info.vidmask && info.base && info.step) {
+               for (i = 0; i < info.vidmask + 1; i++) {
+                       if (info.base >= info.min &&
+                               info.base <= info.max) {
+                               volt->vid[volt->vid_nr].uv = info.base;
+                               volt->vid[volt->vid_nr].vid = i;
+                               volt->vid_nr++;
+                       }
+                       info.base += info.step;
+               }
+               volt->vid_mask = info.vidmask;
+       } else if (data && info.vidmask) {
+               for (i = 0; i < cnt; i++) {
+                       data = nvbios_volt_entry_parse(bios, i, &ver, &hdr,
+                                                         &ivid);
+                       if (data) {
+                               volt->vid[volt->vid_nr].uv = ivid.voltage;
+                               volt->vid[volt->vid_nr].vid = ivid.vid;
+                               volt->vid_nr++;
+                       }
+               }
+               volt->vid_mask = info.vidmask;
+       }
+}
+
 int
 _nouveau_volt_init(struct nouveau_object *object)
 {
@@ -136,10 +171,6 @@ nouveau_volt_create_(struct nouveau_object *parent,
 {
        struct nouveau_bios *bios = nouveau_bios(parent);
        struct nouveau_volt *volt;
-       struct nvbios_volt_entry ivid;
-       struct nvbios_volt info;
-       u8  ver, hdr, cnt, len;
-       u16 data;
        int ret, i;
 
        ret = nouveau_subdev_create_(parent, engine, oclass, 0, "VOLT",
@@ -152,31 +183,9 @@ nouveau_volt_create_(struct nouveau_object *parent,
        volt->set = nouveau_volt_set;
        volt->set_id = nouveau_volt_set_id;
 
-       data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info);
-       if (data && info.vidmask && info.base && info.step) {
-               for (i = 0; i < info.vidmask + 1; i++) {
-                       if (info.base >= info.min &&
-                           info.base <= info.max) {
-                               volt->vid[volt->vid_nr].uv = info.base;
-                               volt->vid[volt->vid_nr].vid = i;
-                               volt->vid_nr++;
-                       }
-                       info.base += info.step;
-               }
-               volt->vid_mask = info.vidmask;
-       } else
-       if (data && info.vidmask) {
-               for (i = 0; i < cnt; i++) {
-                       data = nvbios_volt_entry_parse(bios, i, &ver, &hdr,
-                                                     &ivid);
-                       if (data) {
-                               volt->vid[volt->vid_nr].uv = ivid.voltage;
-                               volt->vid[volt->vid_nr].vid = ivid.vid;
-                               volt->vid_nr++;
-                       }
-               }
-               volt->vid_mask = info.vidmask;
-       }
+       /* Assuming the non-bios device should build the voltage table later */
+       if (bios)
+               nouveau_volt_parse_bios(bios, volt);
 
        if (volt->vid_nr) {
                for (i = 0; i < volt->vid_nr; i++) {
diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/volt/gk20a.c
new file mode 100644 (file)
index 0000000..717368e
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef __KERNEL__
+#include <nouveau_platform.h>
+#endif
+#include <subdev/volt.h>
+
+struct cvb_coef {
+       int c0;
+       int c1;
+       int c2;
+       int c3;
+       int c4;
+       int c5;
+};
+
+struct gk20a_volt_priv {
+       struct nouveau_volt base;
+       struct regulator *vdd;
+};
+
+const struct cvb_coef gk20a_cvb_coef[] = {
+       /* MHz,        c0,     c1,   c2,    c3,     c4,   c5 */
+       /*  72 */ { 1209886, -36468,  515,   417, -13123,  203},
+       /* 108 */ { 1130804, -27659,  296,   298, -10834,  221},
+       /* 180 */ { 1162871, -27110,  247,   238, -10681,  268},
+       /* 252 */ { 1220458, -28654,  247,   179, -10376,  298},
+       /* 324 */ { 1280953, -30204,  247,   119,  -9766,  304},
+       /* 396 */ { 1344547, -31777,  247,   119,  -8545,  292},
+       /* 468 */ { 1420168, -34227,  269,    60,  -7172,  256},
+       /* 540 */ { 1490757, -35955,  274,    60,  -5188,  197},
+       /* 612 */ { 1599112, -42583,  398,     0,  -1831,  119},
+       /* 648 */ { 1366986, -16459, -274,     0,  -3204,   72},
+       /* 684 */ { 1391884, -17078, -274,   -60,  -1526,   30},
+       /* 708 */ { 1415522, -17497, -274,   -60,   -458,    0},
+       /* 756 */ { 1464061, -18331, -274,  -119,   1831,  -72},
+       /* 804 */ { 1524225, -20064, -254,  -119,   4272, -155},
+       /* 852 */ { 1608418, -21643, -269,     0,    763,  -48},
+};
+
+/**
+ * cvb_mv = ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0)
+ */
+static inline int
+gk20a_volt_get_cvb_voltage(int speedo, int s_scale,
+               const struct cvb_coef *coef)
+{
+       int mv;
+
+       mv = DIV_ROUND_CLOSEST(coef->c2 * speedo, s_scale);
+       mv = DIV_ROUND_CLOSEST((mv + coef->c1) * speedo, s_scale) + coef->c0;
+       return mv;
+}
+
+/**
+ * cvb_t_mv =
+ * ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) +
+ * ((c3 * speedo / s_scale + c4 + c5 * T / t_scale) * T / t_scale)
+ */
+static inline int
+gk20a_volt_get_cvb_t_voltage(int speedo, int temp, int s_scale, int t_scale,
+               const struct cvb_coef *coef)
+{
+       int cvb_mv, mv;
+
+       cvb_mv = gk20a_volt_get_cvb_voltage(speedo, s_scale, coef);
+
+       mv = DIV_ROUND_CLOSEST(coef->c3 * speedo, s_scale) + coef->c4 +
+               DIV_ROUND_CLOSEST(coef->c5 * temp, t_scale);
+       mv = DIV_ROUND_CLOSEST(mv * temp, t_scale) + cvb_mv;
+       return mv;
+}
+
+static int
+gk20a_volt_calc_voltage(const struct cvb_coef *coef, int speedo)
+{
+       int mv;
+
+       mv = gk20a_volt_get_cvb_t_voltage(speedo, -10, 100, 10, coef);
+       mv = DIV_ROUND_UP(mv, 1000);
+
+       return mv * 1000;
+}
+
+static int
+gk20a_volt_vid_get(struct nouveau_volt *volt)
+{
+       struct gk20a_volt_priv *priv = (void *)volt;
+       int i, uv;
+
+       uv = regulator_get_voltage(priv->vdd);
+
+       for (i = 0; i < volt->vid_nr; i++)
+               if (volt->vid[i].uv >= uv)
+                       return i;
+
+       return -EINVAL;
+}
+
+static int
+gk20a_volt_vid_set(struct nouveau_volt *volt, u8 vid)
+{
+       struct gk20a_volt_priv *priv = (void *)volt;
+
+       nv_debug(volt, "set voltage as %duv\n", volt->vid[vid].uv);
+       return regulator_set_voltage(priv->vdd, volt->vid[vid].uv, 1200000);
+}
+
+static int
+gk20a_volt_set_id(struct nouveau_volt *volt, u8 id, int condition)
+{
+       struct gk20a_volt_priv *priv = (void *)volt;
+       int prev_uv = regulator_get_voltage(priv->vdd);
+       int target_uv = volt->vid[id].uv;
+       int ret;
+
+       nv_debug(volt, "prev=%d, target=%d, condition=%d\n",
+                       prev_uv, target_uv, condition);
+       if (!condition ||
+               (condition < 0 && target_uv < prev_uv) ||
+               (condition > 0 && target_uv > prev_uv)) {
+               ret = gk20a_volt_vid_set(volt, volt->vid[id].vid);
+       } else {
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static int
+gk20a_volt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+              struct nouveau_oclass *oclass, void *data, u32 size,
+              struct nouveau_object **pobject)
+{
+       struct gk20a_volt_priv *priv;
+       struct nouveau_volt *volt;
+       struct nouveau_platform_device *plat;
+       int i, ret, uv;
+
+       ret = nouveau_volt_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       volt = &priv->base;
+
+       plat = nv_device_to_platform(nv_device(parent));
+
+       uv = regulator_get_voltage(plat->gpu->vdd);
+       nv_info(priv, "The default voltage is %duV\n", uv);
+
+       priv->vdd = plat->gpu->vdd;
+       priv->base.vid_get = gk20a_volt_vid_get;
+       priv->base.vid_set = gk20a_volt_vid_set;
+       priv->base.set_id = gk20a_volt_set_id;
+
+       volt->vid_nr = ARRAY_SIZE(gk20a_cvb_coef);
+       nv_debug(priv, "%s - vid_nr = %d\n", __func__, volt->vid_nr);
+       for (i = 0; i < volt->vid_nr; i++) {
+               volt->vid[i].vid = i;
+               volt->vid[i].uv = gk20a_volt_calc_voltage(&gk20a_cvb_coef[i],
+                                       plat->gpu_speedo);
+               nv_debug(priv, "%2d: vid=%d, uv=%d\n", i, volt->vid[i].vid,
+                                       volt->vid[i].uv);
+       }
+
+       return 0;
+}
+
+struct nouveau_oclass
+gk20a_volt_oclass = {
+       .handle = NV_SUBDEV(VOLT, 0xea),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = gk20a_volt_ctor,
+               .dtor = _nouveau_volt_dtor,
+               .init = _nouveau_volt_init,
+               .fini = _nouveau_volt_fini,
+       },
+};
index 2a03e77abef41ae83d03234501c0eed94348daf5..38402ade68351f9ecab27eed823c0a6d131a75b5 100644 (file)
@@ -614,7 +614,7 @@ nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        int ret;
 
-       ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
+       ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM, false);
        if (ret == 0) {
                if (disp->image[nv_crtc->index])
                        nouveau_bo_unpin(disp->image[nv_crtc->index]);
@@ -1130,7 +1130,7 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num)
        ret = nouveau_bo_new(dev, 64*64*4, 0x100, TTM_PL_FLAG_VRAM,
                             0, 0x0000, NULL, NULL, &nv_crtc->cursor.nvbo);
        if (!ret) {
-               ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
+               ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM, false);
                if (!ret) {
                        ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
                        if (ret)
index 1e9056a8df945917750e9d7effb576e69a9351d9..9f2498571d0953801e30108e439a473b4afff71c 100644 (file)
@@ -126,7 +126,7 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                        return -ERANGE;
        }
 
-       ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM);
+       ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM, false);
        if (ret)
                return ret;
 
@@ -373,7 +373,7 @@ nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        if (crtc_w < src_w || crtc_h < src_h)
                return -ERANGE;
 
-       ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM);
+       ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM, false);
        if (ret)
                return ret;
 
index a24faa5e2a2ae67a5075cb2f9506b9f93fa66083..d39a150000680f0d5c77023670676d322d37bdb3 100644 (file)
@@ -308,7 +308,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
        ret = nouveau_gem_new(dev, PAGE_SIZE, 0, NOUVEAU_GEM_DOMAIN_GART,
                              0, 0, &chan->ntfy);
        if (ret == 0)
-               ret = nouveau_bo_pin(chan->ntfy, TTM_PL_FLAG_TT);
+               ret = nouveau_bo_pin(chan->ntfy, TTM_PL_FLAG_TT, false);
        if (ret)
                goto done;
 
index dae2c96deef86f882888899f64d952950587882d..7df6acc8bb3413ad847db56c5b234764dbd7124e 100644 (file)
@@ -1258,7 +1258,7 @@ olddcb_table(struct drm_device *dev)
                return NULL;
        }
 
-       if (dcb[0] >= 0x41) {
+       if (dcb[0] >= 0x42) {
                NV_WARN(drm, "DCB version 0x%02x unknown\n", dcb[0]);
                return NULL;
        } else
@@ -1481,18 +1481,22 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
                        entry->dpconf.link_bw = 540000;
                        break;
                }
-               switch ((conf & 0x0f000000) >> 24) {
-               case 0xf:
-                       entry->dpconf.link_nr = 4;
-                       break;
-               case 0x3:
-                       entry->dpconf.link_nr = 2;
-                       break;
-               default:
-                       entry->dpconf.link_nr = 1;
-                       break;
+               entry->dpconf.link_nr = (conf & 0x0f000000) >> 24;
+               if (dcb->version < 0x41) {
+                       switch (entry->dpconf.link_nr) {
+                       case 0xf:
+                               entry->dpconf.link_nr = 4;
+                               break;
+                       case 0x3:
+                               entry->dpconf.link_nr = 2;
+                               break;
+                       default:
+                               entry->dpconf.link_nr = 1;
+                               break;
+                       }
                }
                link = entry->dpconf.sor.link;
+               entry->i2c_index += NV_I2C_AUX(0);
                break;
        case DCB_OUTPUT_TMDS:
                if (dcb->version >= 0x40) {
index 3d474ac03f8847c7985c2c664a88bed1cfa189b0..21ec561edc999458c5a8d4f1a99be19e67070ca0 100644 (file)
@@ -214,6 +214,9 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
        nvbo->tile_flags = tile_flags;
        nvbo->bo.bdev = &drm->ttm.bdev;
 
+       if (!nv_device_is_cpu_coherent(nvkm_device(&drm->device)))
+               nvbo->force_coherent = flags & TTM_PL_FLAG_UNCACHED;
+
        nvbo->page_shift = 12;
        if (drm->client.vm) {
                if (!(flags & TTM_PL_FLAG_TT) && size > 256 * 1024)
@@ -291,8 +294,9 @@ void
 nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy)
 {
        struct ttm_placement *pl = &nvbo->placement;
-       uint32_t flags = TTM_PL_MASK_CACHING |
-               (nvbo->pin_refcnt ? TTM_PL_FLAG_NO_EVICT : 0);
+       uint32_t flags = (nvbo->force_coherent ? TTM_PL_FLAG_UNCACHED :
+                                                TTM_PL_MASK_CACHING) |
+                        (nvbo->pin_refcnt ? TTM_PL_FLAG_NO_EVICT : 0);
 
        pl->placement = nvbo->placements;
        set_placement_list(nvbo->placements, &pl->num_placement,
@@ -306,42 +310,75 @@ nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy)
 }
 
 int
-nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype)
+nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype, bool contig)
 {
        struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
        struct ttm_buffer_object *bo = &nvbo->bo;
+       bool force = false, evict = false;
        int ret;
 
        ret = ttm_bo_reserve(bo, false, false, false, NULL);
        if (ret)
-               goto out;
+               return ret;
 
-       if (nvbo->pin_refcnt && !(memtype & (1 << bo->mem.mem_type))) {
-               NV_ERROR(drm, "bo %p pinned elsewhere: 0x%08x vs 0x%08x\n", bo,
-                        1 << bo->mem.mem_type, memtype);
-               ret = -EINVAL;
-               goto out;
+       if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA &&
+           memtype == TTM_PL_FLAG_VRAM && contig) {
+               if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) {
+                       if (bo->mem.mem_type == TTM_PL_VRAM) {
+                               struct nouveau_mem *mem = bo->mem.mm_node;
+                               if (!list_is_singular(&mem->regions))
+                                       evict = true;
+                       }
+                       nvbo->tile_flags &= ~NOUVEAU_GEM_TILE_NONCONTIG;
+                       force = true;
+               }
        }
 
-       if (nvbo->pin_refcnt++)
+       if (nvbo->pin_refcnt) {
+               if (!(memtype & (1 << bo->mem.mem_type)) || evict) {
+                       NV_ERROR(drm, "bo %p pinned elsewhere: "
+                                     "0x%08x vs 0x%08x\n", bo,
+                                1 << bo->mem.mem_type, memtype);
+                       ret = -EBUSY;
+               }
+               nvbo->pin_refcnt++;
                goto out;
+       }
 
+       if (evict) {
+               nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT, 0);
+               ret = nouveau_bo_validate(nvbo, false, false);
+               if (ret)
+                       goto out;
+       }
+
+       nvbo->pin_refcnt++;
        nouveau_bo_placement_set(nvbo, memtype, 0);
 
+       /* drop pin_refcnt temporarily, so we don't trip the assertion
+        * in nouveau_bo_move() that makes sure we're not trying to
+        * move a pinned buffer
+        */
+       nvbo->pin_refcnt--;
        ret = nouveau_bo_validate(nvbo, false, false);
-       if (ret == 0) {
-               switch (bo->mem.mem_type) {
-               case TTM_PL_VRAM:
-                       drm->gem.vram_available -= bo->mem.size;
-                       break;
-               case TTM_PL_TT:
-                       drm->gem.gart_available -= bo->mem.size;
-                       break;
-               default:
-                       break;
-               }
+       if (ret)
+               goto out;
+       nvbo->pin_refcnt++;
+
+       switch (bo->mem.mem_type) {
+       case TTM_PL_VRAM:
+               drm->gem.vram_available -= bo->mem.size;
+               break;
+       case TTM_PL_TT:
+               drm->gem.gart_available -= bo->mem.size;
+               break;
+       default:
+               break;
        }
+
 out:
+       if (force && ret)
+               nvbo->tile_flags |= NOUVEAU_GEM_TILE_NONCONTIG;
        ttm_bo_unreserve(bo);
        return ret;
 }
@@ -392,7 +429,14 @@ nouveau_bo_map(struct nouveau_bo *nvbo)
        if (ret)
                return ret;
 
-       ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages, &nvbo->kmap);
+       /*
+        * TTM buffers allocated using the DMA API already have a mapping, let's
+        * use it instead.
+        */
+       if (!nvbo->force_coherent)
+               ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages,
+                                 &nvbo->kmap);
+
        ttm_bo_unreserve(&nvbo->bo);
        return ret;
 }
@@ -400,10 +444,57 @@ nouveau_bo_map(struct nouveau_bo *nvbo)
 void
 nouveau_bo_unmap(struct nouveau_bo *nvbo)
 {
-       if (nvbo)
+       if (!nvbo)
+               return;
+
+       /*
+        * TTM buffers allocated using the DMA API already had a coherent
+        * mapping which we used, no need to unmap.
+        */
+       if (!nvbo->force_coherent)
                ttm_bo_kunmap(&nvbo->kmap);
 }
 
+void
+nouveau_bo_sync_for_device(struct nouveau_bo *nvbo)
+{
+       struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
+       struct nouveau_device *device = nvkm_device(&drm->device);
+       struct ttm_dma_tt *ttm_dma = (struct ttm_dma_tt *)nvbo->bo.ttm;
+       int i;
+
+       if (!ttm_dma)
+               return;
+
+       /* Don't waste time looping if the object is coherent */
+       if (nvbo->force_coherent)
+               return;
+
+       for (i = 0; i < ttm_dma->ttm.num_pages; i++)
+               dma_sync_single_for_device(nv_device_base(device),
+                       ttm_dma->dma_address[i], PAGE_SIZE, DMA_TO_DEVICE);
+}
+
+void
+nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo)
+{
+       struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
+       struct nouveau_device *device = nvkm_device(&drm->device);
+       struct ttm_dma_tt *ttm_dma = (struct ttm_dma_tt *)nvbo->bo.ttm;
+       int i;
+
+       if (!ttm_dma)
+               return;
+
+       /* Don't waste time looping if the object is coherent */
+       if (nvbo->force_coherent)
+               return;
+
+       for (i = 0; i < ttm_dma->ttm.num_pages; i++)
+               dma_sync_single_for_cpu(nv_device_base(device),
+                       ttm_dma->dma_address[i], PAGE_SIZE, DMA_FROM_DEVICE);
+}
+
 int
 nouveau_bo_validate(struct nouveau_bo *nvbo, bool interruptible,
                    bool no_wait_gpu)
@@ -415,15 +506,41 @@ nouveau_bo_validate(struct nouveau_bo *nvbo, bool interruptible,
        if (ret)
                return ret;
 
+       nouveau_bo_sync_for_device(nvbo);
+
        return 0;
 }
 
+static inline void *
+_nouveau_bo_mem_index(struct nouveau_bo *nvbo, unsigned index, void *mem, u8 sz)
+{
+       struct ttm_dma_tt *dma_tt;
+       u8 *m = mem;
+
+       index *= sz;
+
+       if (m) {
+               /* kmap'd address, return the corresponding offset */
+               m += index;
+       } else {
+               /* DMA-API mapping, lookup the right address */
+               dma_tt = (struct ttm_dma_tt *)nvbo->bo.ttm;
+               m = dma_tt->cpu_address[index / PAGE_SIZE];
+               m += index % PAGE_SIZE;
+       }
+
+       return m;
+}
+#define nouveau_bo_mem_index(o, i, m) _nouveau_bo_mem_index(o, i, m, sizeof(*m))
+
 u16
 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index)
 {
        bool is_iomem;
        u16 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem);
-       mem = &mem[index];
+
+       mem = nouveau_bo_mem_index(nvbo, index, mem);
+
        if (is_iomem)
                return ioread16_native((void __force __iomem *)mem);
        else
@@ -435,7 +552,9 @@ nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val)
 {
        bool is_iomem;
        u16 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem);
-       mem = &mem[index];
+
+       mem = nouveau_bo_mem_index(nvbo, index, mem);
+
        if (is_iomem)
                iowrite16_native(val, (void __force __iomem *)mem);
        else
@@ -447,7 +566,9 @@ nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index)
 {
        bool is_iomem;
        u32 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem);
-       mem = &mem[index];
+
+       mem = nouveau_bo_mem_index(nvbo, index, mem);
+
        if (is_iomem)
                return ioread32_native((void __force __iomem *)mem);
        else
@@ -459,7 +580,9 @@ nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val)
 {
        bool is_iomem;
        u32 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem);
-       mem = &mem[index];
+
+       mem = nouveau_bo_mem_index(nvbo, index, mem);
+
        if (is_iomem)
                iowrite32_native(val, (void __force __iomem *)mem);
        else
@@ -1184,6 +1307,9 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
        struct nouveau_drm_tile *new_tile = NULL;
        int ret = 0;
 
+       if (nvbo->pin_refcnt)
+               NV_WARN(drm, "Moving pinned object %p!\n", nvbo);
+
        if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) {
                ret = nouveau_bo_vm_bind(bo, new_mem, &new_tile);
                if (ret)
@@ -1376,6 +1502,14 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
        dev = drm->dev;
        pdev = nv_device_base(device);
 
+       /*
+        * Objects matching this condition have been marked as force_coherent,
+        * so use the DMA API for them.
+        */
+       if (!nv_device_is_cpu_coherent(device) &&
+           ttm->caching_state == tt_uncached)
+               return ttm_dma_populate(ttm_dma, dev->dev);
+
 #if __OS_HAS_AGP
        if (drm->agp.stat == ENABLED) {
                return ttm_agp_tt_populate(ttm);
@@ -1433,6 +1567,14 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
        dev = drm->dev;
        pdev = nv_device_base(device);
 
+       /*
+        * Objects matching this condition have been marked as force_coherent,
+        * so use the DMA API for them.
+        */
+       if (!nv_device_is_cpu_coherent(device) &&
+           ttm->caching_state == tt_uncached)
+               ttm_dma_unpopulate(ttm_dma, dev->dev);
+
 #if __OS_HAS_AGP
        if (drm->agp.stat == ENABLED) {
                ttm_agp_tt_unpopulate(ttm);
index 22d2c764d80bd17c9fe755abc56b225722eee513..072222efeeb765467605f844d22e340180cda048 100644 (file)
@@ -13,6 +13,7 @@ struct nouveau_bo {
        u32 valid_domains;
        struct ttm_place placements[3];
        struct ttm_place busy_placements[3];
+       bool force_coherent;
        struct ttm_bo_kmap_obj kmap;
        struct list_head head;
 
@@ -72,7 +73,7 @@ int  nouveau_bo_new(struct drm_device *, int size, int align, u32 flags,
                    u32 tile_mode, u32 tile_flags, struct sg_table *sg,
                    struct reservation_object *robj,
                    struct nouveau_bo **);
-int  nouveau_bo_pin(struct nouveau_bo *, u32 flags);
+int  nouveau_bo_pin(struct nouveau_bo *, u32 flags, bool contig);
 int  nouveau_bo_unpin(struct nouveau_bo *);
 int  nouveau_bo_map(struct nouveau_bo *);
 void nouveau_bo_unmap(struct nouveau_bo *);
@@ -84,6 +85,8 @@ void nouveau_bo_wr32(struct nouveau_bo *, unsigned index, u32 val);
 void nouveau_bo_fence(struct nouveau_bo *, struct nouveau_fence *, bool exclusive);
 int  nouveau_bo_validate(struct nouveau_bo *, bool interruptible,
                         bool no_wait_gpu);
+void nouveau_bo_sync_for_device(struct nouveau_bo *nvbo);
+void nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo);
 
 struct nouveau_vma *
 nouveau_bo_vma_find(struct nouveau_bo *, struct nouveau_vm *);
index fd3dbd59d73e18113a6ef357e658570c113155be..aff9099aae6cca23b6e51247ee07068f23b691c1 100644 (file)
@@ -102,14 +102,14 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
        chan->drm = drm;
 
        /* allocate memory for dma push buffer */
-       target = TTM_PL_FLAG_TT;
+       target = TTM_PL_FLAG_TT | TTM_PL_FLAG_UNCACHED;
        if (nouveau_vram_pushbuf)
                target = TTM_PL_FLAG_VRAM;
 
        ret = nouveau_bo_new(drm->dev, size, 0, target, 0, 0, NULL, NULL,
                            &chan->push.buffer);
        if (ret == 0) {
-               ret = nouveau_bo_pin(chan->push.buffer, target);
+               ret = nouveau_bo_pin(chan->push.buffer, target, false);
                if (ret == 0)
                        ret = nouveau_bo_map(chan->push.buffer);
        }
@@ -285,7 +285,6 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
        struct nouveau_software_chan *swch;
        struct nv_dma_v0 args = {};
        int ret, i;
-       bool save;
 
        nvif_object_map(chan->object);
 
@@ -387,11 +386,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
        }
 
        /* initialise synchronisation */
-       save = cli->base.super;
-       cli->base.super = true; /* hack until fencenv50 fixed */
-       ret = nouveau_fence(chan->drm)->context_new(chan);
-       cli->base.super = save;
-       return ret;
+       return nouveau_fence(chan->drm)->context_new(chan);
 }
 
 int
index a88e6927f5713e29a0db95a769dd16401f9f920f..5d93902a91ab038cfe040197f767c0de05d7931f 100644 (file)
@@ -479,6 +479,7 @@ nouveau_display_create(struct drm_device *dev)
 
        if (nouveau_modeset != 2 && drm->vbios.dcb.entries) {
                static const u16 oclass[] = {
+                       GM204_DISP,
                        GM107_DISP,
                        GK110_DISP,
                        GK104_DISP,
@@ -568,9 +569,10 @@ nouveau_display_suspend(struct drm_device *dev, bool runtime)
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-
-               nouveau_bo_unmap(nv_crtc->cursor.nvbo);
-               nouveau_bo_unpin(nv_crtc->cursor.nvbo);
+               if (nv_crtc->cursor.nvbo) {
+                       nouveau_bo_unmap(nv_crtc->cursor.nvbo);
+                       nouveau_bo_unpin(nv_crtc->cursor.nvbo);
+               }
        }
 
        return 0;
@@ -591,15 +593,17 @@ nouveau_display_resume(struct drm_device *dev, bool runtime)
                if (!nouveau_fb || !nouveau_fb->nvbo)
                        continue;
 
-               ret = nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM);
+               ret = nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM, true);
                if (ret)
                        NV_ERROR(drm, "Could not pin framebuffer\n");
        }
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+               if (!nv_crtc->cursor.nvbo)
+                       continue;
 
-               ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
+               ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM, true);
                if (!ret)
                        ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
                if (ret)
@@ -630,9 +634,10 @@ nouveau_display_resume(struct drm_device *dev, bool runtime)
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-               u32 offset = nv_crtc->cursor.nvbo->bo.offset;
 
-               nv_crtc->cursor.set_offset(nv_crtc, offset);
+               if (!nv_crtc->cursor.nvbo)
+                       continue;
+               nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.offset);
                nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x,
                                                 nv_crtc->cursor_saved_y);
        }
@@ -710,7 +715,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                return -ENOMEM;
 
        if (new_bo != old_bo) {
-               ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
+               ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM, true);
                if (ret)
                        goto fail_free;
        }
@@ -871,6 +876,7 @@ nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
        if (ret)
                return ret;
 
+       bo->gem.dumb = true;
        ret = drm_gem_handle_create(file_priv, &bo->gem, &args->handle);
        drm_gem_object_unreference_unlocked(&bo->gem);
        return ret;
@@ -886,6 +892,14 @@ nouveau_display_dumb_map_offset(struct drm_file *file_priv,
        gem = drm_gem_object_lookup(dev, file_priv, handle);
        if (gem) {
                struct nouveau_bo *bo = nouveau_gem_object(gem);
+
+               /*
+                * We don't allow dumb mmaps on objects created using another
+                * interface.
+                */
+               WARN_ONCE(!(gem->dumb || gem->import_attach),
+                         "Illegal dumb map of accelerated buffer.\n");
+
                *poffset = drm_vma_node_offset_addr(&bo->bo.vma_node);
                drm_gem_object_unreference_unlocked(gem);
                return 0;
index 57238076049f6fe16717ba6626bca954b1910aeb..afb93bb72f97949135e38b352b902b5d31a66034 100644 (file)
@@ -613,27 +613,6 @@ fail_display:
        return ret;
 }
 
-int nouveau_pmops_suspend(struct device *dev)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct drm_device *drm_dev = pci_get_drvdata(pdev);
-       int ret;
-
-       if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF ||
-           drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF)
-               return 0;
-
-       ret = nouveau_do_suspend(drm_dev, false);
-       if (ret)
-               return ret;
-
-       pci_save_state(pdev);
-       pci_disable_device(pdev);
-       pci_ignore_hotplug(pdev);
-       pci_set_power_state(pdev, PCI_D3hot);
-       return 0;
-}
-
 static int
 nouveau_do_resume(struct drm_device *dev, bool runtime)
 {
@@ -668,7 +647,30 @@ nouveau_do_resume(struct drm_device *dev, bool runtime)
        return 0;
 }
 
-int nouveau_pmops_resume(struct device *dev)
+int
+nouveau_pmops_suspend(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct drm_device *drm_dev = pci_get_drvdata(pdev);
+       int ret;
+
+       if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF ||
+           drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF)
+               return 0;
+
+       ret = nouveau_do_suspend(drm_dev, false);
+       if (ret)
+               return ret;
+
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+       pci_ignore_hotplug(pdev);
+       pci_set_power_state(pdev, PCI_D3hot);
+       return 0;
+}
+
+int
+nouveau_pmops_resume(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
@@ -688,20 +690,121 @@ int nouveau_pmops_resume(struct device *dev)
        return nouveau_do_resume(drm_dev, false);
 }
 
-static int nouveau_pmops_freeze(struct device *dev)
+static int
+nouveau_pmops_freeze(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
        return nouveau_do_suspend(drm_dev, false);
 }
 
-static int nouveau_pmops_thaw(struct device *dev)
+static int
+nouveau_pmops_thaw(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
        return nouveau_do_resume(drm_dev, false);
 }
 
+static int
+nouveau_pmops_runtime_suspend(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct drm_device *drm_dev = pci_get_drvdata(pdev);
+       int ret;
+
+       if (nouveau_runtime_pm == 0) {
+               pm_runtime_forbid(dev);
+               return -EBUSY;
+       }
+
+       /* are we optimus enabled? */
+       if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) {
+               DRM_DEBUG_DRIVER("failing to power off - not optimus\n");
+               pm_runtime_forbid(dev);
+               return -EBUSY;
+       }
+
+       nv_debug_level(SILENT);
+       drm_kms_helper_poll_disable(drm_dev);
+       vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
+       nouveau_switcheroo_optimus_dsm();
+       ret = nouveau_do_suspend(drm_dev, true);
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, PCI_D3cold);
+       drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF;
+       return ret;
+}
+
+static int
+nouveau_pmops_runtime_resume(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct drm_device *drm_dev = pci_get_drvdata(pdev);
+       struct nvif_device *device = &nouveau_drm(drm_dev)->device;
+       int ret;
+
+       if (nouveau_runtime_pm == 0)
+               return -EINVAL;
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+       ret = pci_enable_device(pdev);
+       if (ret)
+               return ret;
+       pci_set_master(pdev);
+
+       ret = nouveau_do_resume(drm_dev, true);
+       drm_kms_helper_poll_enable(drm_dev);
+       /* do magic */
+       nvif_mask(device, 0x88488, (1 << 25), (1 << 25));
+       vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
+       drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
+       nv_debug_level(NORMAL);
+       return ret;
+}
+
+static int
+nouveau_pmops_runtime_idle(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct drm_device *drm_dev = pci_get_drvdata(pdev);
+       struct nouveau_drm *drm = nouveau_drm(drm_dev);
+       struct drm_crtc *crtc;
+
+       if (nouveau_runtime_pm == 0) {
+               pm_runtime_forbid(dev);
+               return -EBUSY;
+       }
+
+       /* are we optimus enabled? */
+       if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) {
+               DRM_DEBUG_DRIVER("failing to power off - not optimus\n");
+               pm_runtime_forbid(dev);
+               return -EBUSY;
+       }
+
+       /* if we have a hdmi audio device - make sure it has a driver loaded */
+       if (drm->hdmi_device) {
+               if (!drm->hdmi_device->driver) {
+                       DRM_DEBUG_DRIVER("failing to power off - no HDMI audio driver loaded\n");
+                       pm_runtime_mark_last_busy(dev);
+                       return -EBUSY;
+               }
+       }
+
+       list_for_each_entry(crtc, &drm->dev->mode_config.crtc_list, head) {
+               if (crtc->enabled) {
+                       DRM_DEBUG_DRIVER("failing to power off - crtc active\n");
+                       return -EBUSY;
+               }
+       }
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_autosuspend(dev);
+       /* we don't want the main rpm_idle to call suspend - we want to autosuspend */
+       return 1;
+}
 
 static int
 nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv)
@@ -908,103 +1011,6 @@ nouveau_drm_pci_table[] = {
        {}
 };
 
-static int nouveau_pmops_runtime_suspend(struct device *dev)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct drm_device *drm_dev = pci_get_drvdata(pdev);
-       int ret;
-
-       if (nouveau_runtime_pm == 0) {
-               pm_runtime_forbid(dev);
-               return -EBUSY;
-       }
-
-       /* are we optimus enabled? */
-       if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) {
-               DRM_DEBUG_DRIVER("failing to power off - not optimus\n");
-               pm_runtime_forbid(dev);
-               return -EBUSY;
-       }
-
-       nv_debug_level(SILENT);
-       drm_kms_helper_poll_disable(drm_dev);
-       vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
-       nouveau_switcheroo_optimus_dsm();
-       ret = nouveau_do_suspend(drm_dev, true);
-       pci_save_state(pdev);
-       pci_disable_device(pdev);
-       pci_set_power_state(pdev, PCI_D3cold);
-       drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF;
-       return ret;
-}
-
-static int nouveau_pmops_runtime_resume(struct device *dev)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct drm_device *drm_dev = pci_get_drvdata(pdev);
-       struct nvif_device *device = &nouveau_drm(drm_dev)->device;
-       int ret;
-
-       if (nouveau_runtime_pm == 0)
-               return -EINVAL;
-
-       pci_set_power_state(pdev, PCI_D0);
-       pci_restore_state(pdev);
-       ret = pci_enable_device(pdev);
-       if (ret)
-               return ret;
-       pci_set_master(pdev);
-
-       ret = nouveau_do_resume(drm_dev, true);
-       drm_kms_helper_poll_enable(drm_dev);
-       /* do magic */
-       nvif_mask(device, 0x88488, (1 << 25), (1 << 25));
-       vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
-       drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
-       nv_debug_level(NORMAL);
-       return ret;
-}
-
-static int nouveau_pmops_runtime_idle(struct device *dev)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct drm_device *drm_dev = pci_get_drvdata(pdev);
-       struct nouveau_drm *drm = nouveau_drm(drm_dev);
-       struct drm_crtc *crtc;
-
-       if (nouveau_runtime_pm == 0) {
-               pm_runtime_forbid(dev);
-               return -EBUSY;
-       }
-
-       /* are we optimus enabled? */
-       if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) {
-               DRM_DEBUG_DRIVER("failing to power off - not optimus\n");
-               pm_runtime_forbid(dev);
-               return -EBUSY;
-       }
-
-       /* if we have a hdmi audio device - make sure it has a driver loaded */
-       if (drm->hdmi_device) {
-               if (!drm->hdmi_device->driver) {
-                       DRM_DEBUG_DRIVER("failing to power off - no HDMI audio driver loaded\n");
-                       pm_runtime_mark_last_busy(dev);
-                       return -EBUSY;
-               }
-       }
-
-       list_for_each_entry(crtc, &drm->dev->mode_config.crtc_list, head) {
-               if (crtc->enabled) {
-                       DRM_DEBUG_DRIVER("failing to power off - crtc active\n");
-                       return -EBUSY;
-               }
-       }
-       pm_runtime_mark_last_busy(dev);
-       pm_runtime_autosuspend(dev);
-       /* we don't want the main rpm_idle to call suspend - we want to autosuspend */
-       return 1;
-}
-
 static void nouveau_display_options(void)
 {
        DRM_DEBUG_DRIVER("Loading Nouveau with parameters:\n");
index 593ef8a2a069e16b4fdf96e9c95b67ca8ebd1b95..3ed12a8cfc914520fc097ac98e5e16e63ed0d532 100644 (file)
@@ -341,7 +341,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
                goto out;
        }
 
-       ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM);
+       ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, false);
        if (ret) {
                NV_ERROR(drm, "failed to pin fb: %d\n", ret);
                goto out_unref;
@@ -498,6 +498,23 @@ nouveau_fbcon_set_suspend_work(struct work_struct *work)
        console_unlock();
 }
 
+void
+nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
+{
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       if (drm->fbcon) {
+               if (state == FBINFO_STATE_RUNNING) {
+                       schedule_work(&drm->fbcon->work);
+                       return;
+               }
+               flush_work(&drm->fbcon->work);
+               console_lock();
+               fb_set_suspend(drm->fbcon->helper.fbdev, state);
+               nouveau_fbcon_accel_save_disable(dev);
+               console_unlock();
+       }
+}
+
 int
 nouveau_fbcon_init(struct drm_device *dev)
 {
@@ -557,20 +574,3 @@ nouveau_fbcon_fini(struct drm_device *dev)
        kfree(drm->fbcon);
        drm->fbcon = NULL;
 }
-
-void
-nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       if (drm->fbcon) {
-               if (state == FBINFO_STATE_RUNNING) {
-                       schedule_work(&drm->fbcon->work);
-                       return;
-               }
-               flush_work(&drm->fbcon->work);
-               console_lock();
-               fb_set_suspend(drm->fbcon->helper.fbdev, state);
-               nouveau_fbcon_accel_save_disable(dev);
-               console_unlock();
-       }
-}
index 36951ee4b1571807d9a1f85c796f00b232e043d6..28d51a22a4bf18b5729f8f4e9cd159c830cbbfca 100644 (file)
@@ -444,6 +444,9 @@ validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli,
        list_for_each_entry(nvbo, list, entry) {
                struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index];
 
+               WARN_ONCE(nvbo->gem.dumb,
+                         "GPU use of dumb buffer is illegal.\n");
+
                ret = nouveau_gem_set_domain(&nvbo->gem, b->read_domains,
                                             b->write_domains,
                                             b->valid_domains);
@@ -867,6 +870,7 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
                else
                        ret = lret;
        }
+       nouveau_bo_sync_for_cpu(nvbo);
        drm_gem_object_unreference_unlocked(gem);
 
        return ret;
@@ -876,6 +880,17 @@ int
 nouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data,
                           struct drm_file *file_priv)
 {
+       struct drm_nouveau_gem_cpu_fini *req = data;
+       struct drm_gem_object *gem;
+       struct nouveau_bo *nvbo;
+
+       gem = drm_gem_object_lookup(dev, file_priv, req->handle);
+       if (!gem)
+               return -ENOENT;
+       nvbo = nouveau_gem_object(gem);
+
+       nouveau_bo_sync_for_device(nvbo);
+       drm_gem_object_unreference_unlocked(gem);
        return 0;
 }
 
index 246a824c16ca9a88acc05c5f464a0d7a5f387a23..b307bbedd4c43548387557ca0cd4a44a5654ae4e 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/of.h>
 #include <linux/reset.h>
 #include <linux/regulator/consumer.h>
+#include <soc/tegra/fuse.h>
 #include <soc/tegra/pmc.h>
 
 #include "nouveau_drm.h"
@@ -128,6 +129,7 @@ static int nouveau_platform_probe(struct platform_device *pdev)
        }
 
        device->gpu = gpu;
+       device->gpu_speedo = tegra_sku_info.gpu_speedo_value;
 
        err = drm_dev_register(drm, 0);
        if (err < 0)
index 91f66504900ef21bbdd2de8488649c58dccd5cfa..58c28b5653d5a8ade0718edd509646888bdf9a6d 100644 (file)
@@ -41,6 +41,8 @@ struct nouveau_platform_device {
        struct nouveau_device device;
 
        struct nouveau_platform_gpu *gpu;
+
+       int gpu_speedo;
 };
 
 #define nv_device_to_platform(d)                                               \
index 228226ab27fc1b55883d9d7bcf6066f5c3852bc5..dd32ad6db53d2525bfbdde846a87f8b369269cc8 100644 (file)
@@ -93,7 +93,7 @@ int nouveau_gem_prime_pin(struct drm_gem_object *obj)
        int ret;
 
        /* pin buffer into GTT */
-       ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_TT);
+       ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_TT, false);
        if (ret)
                return -EINVAL;
 
index 40b461c7d5c565c0471c5f3b80f09221a7d42a8b..57860cfa1de5c2e2ebb2947773d8e0ff12f613a0 100644 (file)
@@ -131,7 +131,7 @@ nv17_fence_create(struct nouveau_drm *drm)
        ret = nouveau_bo_new(drm->dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
                             0, 0x0000, NULL, NULL, &priv->bo);
        if (!ret) {
-               ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
+               ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM, false);
                if (!ret) {
                        ret = nouveau_bo_map(priv->bo);
                        if (ret)
index 6f77a8dec3db4fe163b1082a8da0b95d3b0631c7..490b90866baf4cae9feeb4880d33d03e47528bdc 100644 (file)
@@ -66,15 +66,29 @@ static int
 nv50_chan_create(struct nvif_object *disp, const u32 *oclass, u8 head,
                 void *data, u32 size, struct nv50_chan *chan)
 {
+       const u32 handle = (oclass[0] << 16) | head;
+       u32 sclass[8];
+       int ret, i;
+
+       ret = nvif_object_sclass(disp, sclass, ARRAY_SIZE(sclass));
+       WARN_ON(ret > ARRAY_SIZE(sclass));
+       if (ret < 0)
+               return ret;
+
        while (oclass[0]) {
-               int ret = nvif_object_init(disp, NULL, (oclass[0] << 16) | head,
-                                          oclass[0], data, size,
-                                         &chan->user);
-               if (oclass++, ret == 0) {
-                       nvif_object_map(&chan->user);
-                       return ret;
+               for (i = 0; i < ARRAY_SIZE(sclass); i++) {
+                       if (sclass[i] == oclass[0]) {
+                               ret = nvif_object_init(disp, NULL, handle,
+                                                      oclass[0], data, size,
+                                                      &chan->user);
+                               if (ret == 0)
+                                       nvif_object_map(&chan->user);
+                               return ret;
+                       }
                }
+               oclass++;
        }
+
        return -ENOSYS;
 }
 
@@ -111,6 +125,7 @@ nv50_pioc_create(struct nvif_object *disp, const u32 *oclass, u8 head,
 
 struct nv50_curs {
        struct nv50_pioc base;
+       struct nouveau_bo *image;
 };
 
 static int
@@ -266,6 +281,7 @@ nv50_core_create(struct nvif_object *disp, u64 syncbuf, struct nv50_mast *core)
                .pushbuf = 0xb0007d00,
        };
        static const u32 oclass[] = {
+               GM204_DISP_CORE_CHANNEL_DMA,
                GM107_DISP_CORE_CHANNEL_DMA,
                GK110_DISP_CORE_CHANNEL_DMA,
                GK104_DISP_CORE_CHANNEL_DMA,
@@ -425,8 +441,21 @@ evo_kick(u32 *push, void *evoc)
        mutex_unlock(&dmac->lock);
 }
 
+#if 1
 #define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m))
 #define evo_data(p,d)   *((p)++) = (d)
+#else
+#define evo_mthd(p,m,s) do {                                                   \
+       const u32 _m = (m), _s = (s);                                          \
+       printk(KERN_ERR "%04x %d %s\n", _m, _s, __func__);                     \
+       *((p)++) = ((_s << 18) | _m);                                          \
+} while(0)
+#define evo_data(p,d) do {                                                     \
+       const u32 _d = (d);                                                    \
+       printk(KERN_ERR "\t%08x\n", _d);                                       \
+       *((p)++) = _d;                                                         \
+} while(0)
+#endif
 
 static bool
 evo_sync_wait(void *data)
@@ -888,23 +917,24 @@ static void
 nv50_crtc_cursor_show(struct nouveau_crtc *nv_crtc)
 {
        struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
+       struct nv50_curs *curs = nv50_curs(&nv_crtc->base);
        u32 *push = evo_wait(mast, 16);
        if (push) {
                if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) {
                        evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2);
                        evo_data(push, 0x85000000);
-                       evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
+                       evo_data(push, curs->image->bo.offset >> 8);
                } else
                if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
                        evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2);
                        evo_data(push, 0x85000000);
-                       evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
+                       evo_data(push, curs->image->bo.offset >> 8);
                        evo_mthd(push, 0x089c + (nv_crtc->index * 0x400), 1);
                        evo_data(push, mast->base.vram.handle);
                } else {
                        evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2);
                        evo_data(push, 0x85000000);
-                       evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
+                       evo_data(push, curs->image->bo.offset >> 8);
                        evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
                        evo_data(push, mast->base.vram.handle);
                }
@@ -941,8 +971,9 @@ static void
 nv50_crtc_cursor_show_hide(struct nouveau_crtc *nv_crtc, bool show, bool update)
 {
        struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
+       struct nv50_curs *curs = nv50_curs(&nv_crtc->base);
 
-       if (show)
+       if (show && curs->image)
                nv50_crtc_cursor_show(nv_crtc);
        else
                nv50_crtc_cursor_hide(nv_crtc);
@@ -1042,7 +1073,7 @@ nv50_crtc_commit(struct drm_crtc *crtc)
                evo_kick(push, mast);
        }
 
-       nv50_crtc_cursor_show_hide(nv_crtc, nv_crtc->cursor.visible, true);
+       nv50_crtc_cursor_show_hide(nv_crtc, true, true);
        nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
 }
 
@@ -1061,7 +1092,7 @@ nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
        struct nv50_head *head = nv50_head(crtc);
        int ret;
 
-       ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
+       ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM, true);
        if (ret == 0) {
                if (head->image)
                        nouveau_bo_unpin(head->image);
@@ -1242,13 +1273,13 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
                     uint32_t handle, uint32_t width, uint32_t height)
 {
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+       struct nv50_curs *curs = nv50_curs(crtc);
        struct drm_device *dev = crtc->dev;
-       struct drm_gem_object *gem;
-       struct nouveau_bo *nvbo;
-       bool visible = (handle != 0);
-       int i, ret = 0;
+       struct drm_gem_object *gem = NULL;
+       struct nouveau_bo *nvbo = NULL;
+       int ret = 0;
 
-       if (visible) {
+       if (handle) {
                if (width != 64 || height != 64)
                        return -EINVAL;
 
@@ -1257,23 +1288,17 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
                        return -ENOENT;
                nvbo = nouveau_gem_object(gem);
 
-               ret = nouveau_bo_map(nvbo);
-               if (ret == 0) {
-                       for (i = 0; i < 64 * 64; i++) {
-                               u32 v = nouveau_bo_rd32(nvbo, i);
-                               nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, v);
-                       }
-                       nouveau_bo_unmap(nvbo);
-               }
-
-               drm_gem_object_unreference_unlocked(gem);
+               ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, true);
        }
 
-       if (visible != nv_crtc->cursor.visible) {
-               nv50_crtc_cursor_show_hide(nv_crtc, visible, true);
-               nv_crtc->cursor.visible = visible;
+       if (ret == 0) {
+               if (curs->image)
+                       nouveau_bo_unpin(curs->image);
+               nouveau_bo_ref(nvbo, &curs->image);
        }
+       drm_gem_object_unreference_unlocked(gem);
 
+       nv50_crtc_cursor_show_hide(nv_crtc, true, true);
        return ret;
 }
 
@@ -1328,10 +1353,10 @@ nv50_crtc_destroy(struct drm_crtc *crtc)
                nouveau_bo_unpin(head->image);
        nouveau_bo_ref(NULL, &head->image);
 
-       nouveau_bo_unmap(nv_crtc->cursor.nvbo);
-       if (nv_crtc->cursor.nvbo)
-               nouveau_bo_unpin(nv_crtc->cursor.nvbo);
-       nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
+       /*XXX: ditto */
+       if (head->curs.image)
+               nouveau_bo_unpin(head->curs.image);
+       nouveau_bo_ref(NULL, &head->curs.image);
 
        nouveau_bo_unmap(nv_crtc->lut.nvbo);
        if (nv_crtc->lut.nvbo)
@@ -1363,16 +1388,6 @@ static const struct drm_crtc_funcs nv50_crtc_func = {
        .page_flip = nouveau_crtc_page_flip,
 };
 
-static void
-nv50_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y)
-{
-}
-
-static void
-nv50_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset)
-{
-}
-
 static int
 nv50_crtc_create(struct drm_device *dev, int index)
 {
@@ -1391,8 +1406,6 @@ nv50_crtc_create(struct drm_device *dev, int index)
        head->base.set_color_vibrance = nv50_crtc_set_color_vibrance;
        head->base.color_vibrance = 50;
        head->base.vibrant_hue = 0;
-       head->base.cursor.set_offset = nv50_cursor_set_offset;
-       head->base.cursor.set_pos = nv50_cursor_set_pos;
        for (i = 0; i < 256; i++) {
                head->base.lut.r[i] = i << 8;
                head->base.lut.g[i] = i << 8;
@@ -1407,7 +1420,7 @@ nv50_crtc_create(struct drm_device *dev, int index)
        ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM,
                             0, 0x0000, NULL, NULL, &head->base.lut.nvbo);
        if (!ret) {
-               ret = nouveau_bo_pin(head->base.lut.nvbo, TTM_PL_FLAG_VRAM);
+               ret = nouveau_bo_pin(head->base.lut.nvbo, TTM_PL_FLAG_VRAM, true);
                if (!ret) {
                        ret = nouveau_bo_map(head->base.lut.nvbo);
                        if (ret)
@@ -1424,22 +1437,6 @@ nv50_crtc_create(struct drm_device *dev, int index)
 
        /* allocate cursor resources */
        ret = nv50_curs_create(disp->disp, index, &head->curs);
-       if (ret)
-               goto out;
-
-       ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM,
-                            0, 0x0000, NULL, NULL, &head->base.cursor.nvbo);
-       if (!ret) {
-               ret = nouveau_bo_pin(head->base.cursor.nvbo, TTM_PL_FLAG_VRAM);
-               if (!ret) {
-                       ret = nouveau_bo_map(head->base.cursor.nvbo);
-                       if (ret)
-                               nouveau_bo_unpin(head->base.lut.nvbo);
-               }
-               if (ret)
-                       nouveau_bo_ref(NULL, &head->base.cursor.nvbo);
-       }
-
        if (ret)
                goto out;
 
@@ -2375,11 +2372,6 @@ nv50_fb_ctor(struct drm_framebuffer *fb)
        u8 kind = nouveau_bo_tile_layout(nvbo) >> 8;
        u8 tile = nvbo->tile_mode;
 
-       if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) {
-               NV_ERROR(drm, "framebuffer requires contiguous bo\n");
-               return -EINVAL;
-       }
-
        if (drm->device.info.chipset >= 0xc0)
                tile >>= 4; /* yep.. */
 
@@ -2493,7 +2485,7 @@ nv50_display_create(struct drm_device *dev)
        ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
                             0, 0x0000, NULL, NULL, &disp->sync);
        if (!ret) {
-               ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM);
+               ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM, true);
                if (!ret) {
                        ret = nouveau_bo_map(disp->sync);
                        if (ret)
index 22d242b37962cc14990174bc97f6876a30e31781..a82d9ea7c6fdeaf2a1fa96863b26a9ccc2b12e00 100644 (file)
@@ -102,7 +102,7 @@ nv50_fence_create(struct nouveau_drm *drm)
        ret = nouveau_bo_new(drm->dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
                             0, 0x0000, NULL, NULL, &priv->bo);
        if (!ret) {
-               ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
+               ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM, false);
                if (!ret) {
                        ret = nouveau_bo_map(priv->bo);
                        if (ret)
index d6c6c87c3f07e2e929e49cf8ca7d41145f8c164b..cb5b88938d451c7f8d70be4a2816d11fe3f25d35 100644 (file)
@@ -234,7 +234,7 @@ nv84_fence_create(struct nouveau_drm *drm)
        ret = nouveau_bo_new(drm->dev, 16 * priv->base.contexts, 0,
                             TTM_PL_FLAG_VRAM, 0, 0, NULL, NULL, &priv->bo);
        if (ret == 0) {
-               ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
+               ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM, false);
                if (ret == 0) {
                        ret = nouveau_bo_map(priv->bo);
                        if (ret)
@@ -246,10 +246,10 @@ nv84_fence_create(struct nouveau_drm *drm)
 
        if (ret == 0)
                ret = nouveau_bo_new(drm->dev, 16 * priv->base.contexts, 0,
-                                    TTM_PL_FLAG_TT, 0, 0, NULL, NULL,
-                                    &priv->bo_gart);
+                                    TTM_PL_FLAG_TT | TTM_PL_FLAG_UNCACHED, 0,
+                                    0, NULL, NULL, &priv->bo_gart);
        if (ret == 0) {
-               ret = nouveau_bo_pin(priv->bo_gart, TTM_PL_FLAG_TT);
+               ret = nouveau_bo_pin(priv->bo_gart, TTM_PL_FLAG_TT, false);
                if (ret == 0) {
                        ret = nouveau_bo_map(priv->bo_gart);
                        if (ret)
index e5a27df0672b5db5d0b21c11f8e46344eb706fa4..4e308eacb27a0c800df134e517753367a8ddf9f5 100644 (file)
@@ -35,6 +35,7 @@
 #define GK104_DISP                                                   0x00009170
 #define GK110_DISP                                                   0x00009270
 #define GM107_DISP                                                   0x00009470
+#define GM204_DISP                                                   0x00009570
 
 #define NV50_DISP_CURSOR                                             0x0000507a
 #define G82_DISP_CURSOR                                              0x0000827a
@@ -65,6 +66,7 @@
 #define GK104_DISP_CORE_CHANNEL_DMA                                  0x0000917d
 #define GK110_DISP_CORE_CHANNEL_DMA                                  0x0000927d
 #define GM107_DISP_CORE_CHANNEL_DMA                                  0x0000947d
+#define GM204_DISP_CORE_CHANNEL_DMA                                  0x0000957d
 
 #define NV50_DISP_OVERLAY_CHANNEL_DMA                                0x0000507e
 #define G82_DISP_OVERLAY_CHANNEL_DMA                                 0x0000827e
@@ -131,6 +133,7 @@ struct nv_device_v0 {
 #define NV_DEVICE_V0_DISABLE_COPY1                        0x0000010000000000ULL
 #define NV_DEVICE_V0_DISABLE_VIC                          0x0000020000000000ULL
 #define NV_DEVICE_V0_DISABLE_VENC                         0x0000040000000000ULL
+#define NV_DEVICE_V0_DISABLE_COPY2                        0x0000080000000000ULL
        __u64 disable;  /* disable particular subsystems */
        __u64 debug0;   /* as above, but *internal* ids, and *NOT* ABI */
 };
index 3c4df1fc26dce053ad8c2408cc8ba42906ae57d6..3f7ac5bc8e03990426c70a2e3c17622fe9edfb53 100644 (file)
@@ -62,6 +62,7 @@ nvif_drivers[] = {
 #else
        &nvif_driver_drm,
        &nvif_driver_lib,
+       &nvif_driver_null,
 #endif
        NULL
 };
index ac4bdb3ea506c518cf87eefc3c2e793cbc8bc23f..8bd39e69229c6103b2a811499ebb3023d29bc0ec 100644 (file)
@@ -17,5 +17,6 @@ struct nvif_driver {
 extern const struct nvif_driver nvif_driver_nvkm;
 extern const struct nvif_driver nvif_driver_drm;
 extern const struct nvif_driver nvif_driver_lib;
+extern const struct nvif_driver nvif_driver_null;
 
 #endif
index e4849413ee80074616d6b6239cea6f0b1b16c5a3..aeb91ed653c9f8d2e410a6b95ed7e194168ef508 100644 (file)
@@ -612,8 +612,7 @@ int omap_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
 {
        union omap_gem_size gsize;
 
-       /* in case someone tries to feed us a completely bogus stride: */
-       args->pitch = align_pitch(args->pitch, args->width, args->bpp);
+       args->pitch = align_pitch(0, args->width, args->bpp);
        args->size = PAGE_ALIGN(args->pitch * args->height);
 
        gsize = (union omap_gem_size){
index 891a4dc608af85f2760ced973c9cf5163743d08f..ee8e2b3a117ef59c183bd4cd63075ea565be98c1 100644 (file)
@@ -388,20 +388,15 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
        struct drm_plane *plane = NULL;
        struct omap_plane *omap_plane;
        struct omap_overlay_info *info;
-       int ret;
 
        DBG("%s: priv=%d", plane_names[id], private_plane);
 
        omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
        if (!omap_plane)
-               goto fail;
+               return NULL;
 
-       ret = drm_flip_work_init(&omap_plane->unpin_work, 16,
+       drm_flip_work_init(&omap_plane->unpin_work,
                        "unpin", unpin_worker);
-       if (ret) {
-               dev_err(dev->dev, "could not allocate unpin FIFO\n");
-               goto fail;
-       }
 
        omap_plane->nformats = omap_framebuffer_get_formats(
                        omap_plane->formats, ARRAY_SIZE(omap_plane->formats),
@@ -443,10 +438,4 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
                omap_plane->info.zorder = id;
 
        return plane;
-
-fail:
-       if (plane)
-               omap_plane_destroy(plane);
-
-       return NULL;
 }
index bee9f72b3a93a2cccb99476ac6433c53c2ed04c7..024e98ef8e4d1bcd7be6b70c648969e529c175e5 100644 (file)
@@ -27,4 +27,17 @@ config DRM_PANEL_S6E8AA0
        select DRM_MIPI_DSI
        select VIDEOMODE_HELPERS
 
+config DRM_PANEL_SHARP_LQ101R1SX01
+       tristate "Sharp LQ101R1SX01 panel"
+       depends on OF
+       depends on DRM_MIPI_DSI
+       help
+         Say Y here if you want to enable support for Sharp LQ101R1SX01
+         TFT-LCD modules. The panel has a 2560x1600 resolution and uses
+         24 bit RGB per pixel. It provides a dual MIPI DSI interface to
+         the host and has a built-in LED backlight.
+
+         To compile this driver as a module, choose M here: the module
+         will be called panel-sharp-lq101r1sx01.
+
 endmenu
index 8b929212fad791e6177d5f50ababb3fa8a1f60aa..4b2a0430804b1813ed02bc713e61590e7a62d849 100644 (file)
@@ -1,3 +1,4 @@
 obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
 obj-$(CONFIG_DRM_PANEL_LD9040) += panel-ld9040.o
 obj-$(CONFIG_DRM_PANEL_S6E8AA0) += panel-s6e8aa0.o
+obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
index 42ac67b21e9fac04d9f0e0599426f0fa48abf4cb..08cf2c588c3df3d4555f72d62d482b51098e5f0e 100644 (file)
@@ -145,7 +145,7 @@ static void ld9040_dcs_write(struct ld9040 *ctx, const u8 *data, size_t len)
        if (ctx->error < 0 || len == 0)
                return;
 
-       dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", len, data);
+       dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", (int)len, data);
        ret = ld9040_spi_write_word(ctx, *data);
 
        while (!ret && --len) {
@@ -154,8 +154,8 @@ static void ld9040_dcs_write(struct ld9040 *ctx, const u8 *data, size_t len)
        }
 
        if (ret) {
-               dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, len,
-                       data);
+               dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret,
+                       (int)len, data);
                ctx->error = ret;
        }
 
@@ -336,17 +336,12 @@ static int ld9040_probe(struct spi_device *spi)
        if (ret < 0)
                return ret;
 
-       ctx->reset_gpio = devm_gpiod_get(dev, "reset");
+       ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
        if (IS_ERR(ctx->reset_gpio)) {
                dev_err(dev, "cannot get reset-gpios %ld\n",
                        PTR_ERR(ctx->reset_gpio));
                return PTR_ERR(ctx->reset_gpio);
        }
-       ret = gpiod_direction_output(ctx->reset_gpio, 1);
-       if (ret < 0) {
-               dev_err(dev, "cannot configure reset-gpios %d\n", ret);
-               return ret;
-       }
 
        spi->bits_per_word = 9;
        ret = spi_setup(spi);
index b5217fe37f02742e87df986280fb69c2097bead9..144b2733e3d70ffd33a71997da4fae29fc8723ec 100644 (file)
@@ -141,10 +141,10 @@ static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t len)
        if (ctx->error < 0)
                return;
 
-       ret = mipi_dsi_dcs_write(dsi, data, len);
+       ret = mipi_dsi_dcs_write_buffer(dsi, data, len);
        if (ret < 0) {
-               dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret, len,
-                       data);
+               dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret,
+                       (int)len, data);
                ctx->error = ret;
        }
 }
@@ -800,27 +800,15 @@ static void s6e8aa0_panel_init(struct s6e8aa0 *ctx)
 }
 
 static void s6e8aa0_set_maximum_return_packet_size(struct s6e8aa0 *ctx,
-                                                  int size)
+                                                  u16 size)
 {
        struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
-       const struct mipi_dsi_host_ops *ops = dsi->host->ops;
-       u8 buf[] = {size, 0};
-       struct mipi_dsi_msg msg = {
-               .channel = dsi->channel,
-               .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
-               .tx_len = sizeof(buf),
-               .tx_buf = buf
-       };
        int ret;
 
        if (ctx->error < 0)
                return;
 
-       if (!ops || !ops->transfer)
-               ret = -EIO;
-       else
-               ret = ops->transfer(dsi->host, &msg);
-
+       ret = mipi_dsi_set_maximum_return_packet_size(dsi, size);
        if (ret < 0) {
                dev_err(ctx->dev,
                        "error %d setting maximum return packet size to %d\n",
@@ -1019,17 +1007,12 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi)
                return ret;
        }
 
-       ctx->reset_gpio = devm_gpiod_get(dev, "reset");
+       ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
        if (IS_ERR(ctx->reset_gpio)) {
                dev_err(dev, "cannot get reset-gpios %ld\n",
                        PTR_ERR(ctx->reset_gpio));
                return PTR_ERR(ctx->reset_gpio);
        }
-       ret = gpiod_direction_output(ctx->reset_gpio, 1);
-       if (ret < 0) {
-               dev_err(dev, "cannot configure reset-gpios %d\n", ret);
-               return ret;
-       }
 
        ctx->brightness = GAMMA_LEVEL_NUM - 1;
 
@@ -1069,7 +1052,6 @@ static struct mipi_dsi_driver s6e8aa0_driver = {
        .remove = s6e8aa0_remove,
        .driver = {
                .name = "panel_s6e8aa0",
-               .owner = THIS_MODULE,
                .of_match_table = s6e8aa0_of_match,
        },
 };
diff --git a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
new file mode 100644 (file)
index 0000000..9d81759
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2014 NVIDIA Corporation
+ *
+ * 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/backlight.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+#include <video/mipi_display.h>
+
+#include <linux/host1x.h>
+
+struct sharp_panel {
+       struct drm_panel base;
+       /* the datasheet refers to them as DSI-LINK1 and DSI-LINK2 */
+       struct mipi_dsi_device *link1;
+       struct mipi_dsi_device *link2;
+
+       struct backlight_device *backlight;
+       struct regulator *supply;
+
+       bool prepared;
+       bool enabled;
+
+       const struct drm_display_mode *mode;
+};
+
+static inline struct sharp_panel *to_sharp_panel(struct drm_panel *panel)
+{
+       return container_of(panel, struct sharp_panel, base);
+}
+
+static int sharp_panel_write(struct sharp_panel *sharp, u16 offset, u8 value)
+{
+       u8 payload[3] = { offset >> 8, offset & 0xff, value };
+       struct mipi_dsi_device *dsi = sharp->link1;
+       ssize_t err;
+
+       err = mipi_dsi_generic_write(dsi, payload, sizeof(payload));
+       if (err < 0) {
+               dev_err(&dsi->dev, "failed to write %02x to %04x: %zd\n",
+                       value, offset, err);
+               return err;
+       }
+
+       err = mipi_dsi_dcs_nop(dsi);
+       if (err < 0) {
+               dev_err(&dsi->dev, "failed to send DCS nop: %zd\n", err);
+               return err;
+       }
+
+       usleep_range(10, 20);
+
+       return 0;
+}
+
+static __maybe_unused int sharp_panel_read(struct sharp_panel *sharp,
+                                          u16 offset, u8 *value)
+{
+       ssize_t err;
+
+       cpu_to_be16s(&offset);
+
+       err = mipi_dsi_generic_read(sharp->link1, &offset, sizeof(offset),
+                                   value, sizeof(*value));
+       if (err < 0)
+               dev_err(&sharp->link1->dev, "failed to read from %04x: %zd\n",
+                       offset, err);
+
+       return err;
+}
+
+static int sharp_panel_disable(struct drm_panel *panel)
+{
+       struct sharp_panel *sharp = to_sharp_panel(panel);
+
+       if (!sharp->enabled)
+               return 0;
+
+       if (sharp->backlight) {
+               sharp->backlight->props.power = FB_BLANK_POWERDOWN;
+               backlight_update_status(sharp->backlight);
+       }
+
+       sharp->enabled = false;
+
+       return 0;
+}
+
+static int sharp_panel_unprepare(struct drm_panel *panel)
+{
+       struct sharp_panel *sharp = to_sharp_panel(panel);
+       int err;
+
+       if (!sharp->prepared)
+               return 0;
+
+       err = mipi_dsi_dcs_set_display_off(sharp->link1);
+       if (err < 0)
+               dev_err(panel->dev, "failed to set display off: %d\n", err);
+
+       err = mipi_dsi_dcs_enter_sleep_mode(sharp->link1);
+       if (err < 0)
+               dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
+
+       msleep(120);
+
+       regulator_disable(sharp->supply);
+
+       sharp->prepared = false;
+
+       return 0;
+}
+
+static int sharp_setup_symmetrical_split(struct mipi_dsi_device *left,
+                                        struct mipi_dsi_device *right,
+                                        const struct drm_display_mode *mode)
+{
+       int err;
+
+       err = mipi_dsi_dcs_set_column_address(left, 0, mode->hdisplay / 2 - 1);
+       if (err < 0) {
+               dev_err(&left->dev, "failed to set column address: %d\n", err);
+               return err;
+       }
+
+       err = mipi_dsi_dcs_set_page_address(left, 0, mode->vdisplay - 1);
+       if (err < 0) {
+               dev_err(&left->dev, "failed to set page address: %d\n", err);
+               return err;
+       }
+
+       err = mipi_dsi_dcs_set_column_address(right, mode->hdisplay / 2,
+                                             mode->hdisplay - 1);
+       if (err < 0) {
+               dev_err(&right->dev, "failed to set column address: %d\n", err);
+               return err;
+       }
+
+       err = mipi_dsi_dcs_set_page_address(right, 0, mode->vdisplay - 1);
+       if (err < 0) {
+               dev_err(&right->dev, "failed to set page address: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+static int sharp_panel_prepare(struct drm_panel *panel)
+{
+       struct sharp_panel *sharp = to_sharp_panel(panel);
+       u8 format = MIPI_DCS_PIXEL_FMT_24BIT;
+       int err;
+
+       if (sharp->prepared)
+               return 0;
+
+       err = regulator_enable(sharp->supply);
+       if (err < 0)
+               return err;
+
+       usleep_range(10000, 20000);
+
+       err = mipi_dsi_dcs_soft_reset(sharp->link1);
+       if (err < 0) {
+               dev_err(panel->dev, "soft reset failed: %d\n", err);
+               goto poweroff;
+       }
+
+       msleep(120);
+
+       err = mipi_dsi_dcs_exit_sleep_mode(sharp->link1);
+       if (err < 0) {
+               dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
+               goto poweroff;
+       }
+
+       /*
+        * The MIPI DCS specification mandates this delay only between the
+        * exit_sleep_mode and enter_sleep_mode commands, so it isn't strictly
+        * necessary here.
+        */
+       /*
+       msleep(120);
+       */
+
+       /* set left-right mode */
+       err = sharp_panel_write(sharp, 0x1000, 0x2a);
+       if (err < 0) {
+               dev_err(panel->dev, "failed to set left-right mode: %d\n", err);
+               goto poweroff;
+       }
+
+       /* enable command mode */
+       err = sharp_panel_write(sharp, 0x1001, 0x01);
+       if (err < 0) {
+               dev_err(panel->dev, "failed to enable command mode: %d\n", err);
+               goto poweroff;
+       }
+
+       err = mipi_dsi_dcs_set_pixel_format(sharp->link1, format);
+       if (err < 0) {
+               dev_err(panel->dev, "failed to set pixel format: %d\n", err);
+               goto poweroff;
+       }
+
+       /*
+        * TODO: The device supports both left-right and even-odd split
+        * configurations, but this driver currently supports only the left-
+        * right split. To support a different mode a mechanism needs to be
+        * put in place to communicate the configuration back to the DSI host
+        * controller.
+        */
+       err = sharp_setup_symmetrical_split(sharp->link1, sharp->link2,
+                                           sharp->mode);
+       if (err < 0) {
+               dev_err(panel->dev, "failed to set up symmetrical split: %d\n",
+                       err);
+               goto poweroff;
+       }
+
+       err = mipi_dsi_dcs_set_display_on(sharp->link1);
+       if (err < 0) {
+               dev_err(panel->dev, "failed to set display on: %d\n", err);
+               goto poweroff;
+       }
+
+       sharp->prepared = true;
+
+       return 0;
+
+poweroff:
+       regulator_disable(sharp->supply);
+       return err;
+}
+
+static int sharp_panel_enable(struct drm_panel *panel)
+{
+       struct sharp_panel *sharp = to_sharp_panel(panel);
+
+       if (sharp->enabled)
+               return 0;
+
+       if (sharp->backlight) {
+               sharp->backlight->props.power = FB_BLANK_UNBLANK;
+               backlight_update_status(sharp->backlight);
+       }
+
+       sharp->enabled = true;
+
+       return 0;
+}
+
+static const struct drm_display_mode default_mode = {
+       .clock = 278000,
+       .hdisplay = 2560,
+       .hsync_start = 2560 + 128,
+       .hsync_end = 2560 + 128 + 64,
+       .htotal = 2560 + 128 + 64 + 64,
+       .vdisplay = 1600,
+       .vsync_start = 1600 + 4,
+       .vsync_end = 1600 + 4 + 8,
+       .vtotal = 1600 + 4 + 8 + 32,
+       .vrefresh = 60,
+};
+
+static int sharp_panel_get_modes(struct drm_panel *panel)
+{
+       struct drm_display_mode *mode;
+
+       mode = drm_mode_duplicate(panel->drm, &default_mode);
+       if (!mode) {
+               dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
+                       default_mode.hdisplay, default_mode.vdisplay,
+                       default_mode.vrefresh);
+               return -ENOMEM;
+       }
+
+       drm_mode_set_name(mode);
+
+       drm_mode_probed_add(panel->connector, mode);
+
+       panel->connector->display_info.width_mm = 217;
+       panel->connector->display_info.height_mm = 136;
+
+       return 1;
+}
+
+static const struct drm_panel_funcs sharp_panel_funcs = {
+       .disable = sharp_panel_disable,
+       .unprepare = sharp_panel_unprepare,
+       .prepare = sharp_panel_prepare,
+       .enable = sharp_panel_enable,
+       .get_modes = sharp_panel_get_modes,
+};
+
+static const struct of_device_id sharp_of_match[] = {
+       { .compatible = "sharp,lq101r1sx01", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, sharp_of_match);
+
+static int sharp_panel_add(struct sharp_panel *sharp)
+{
+       struct device_node *np;
+       int err;
+
+       sharp->mode = &default_mode;
+
+       sharp->supply = devm_regulator_get(&sharp->link1->dev, "power");
+       if (IS_ERR(sharp->supply))
+               return PTR_ERR(sharp->supply);
+
+       np = of_parse_phandle(sharp->link1->dev.of_node, "backlight", 0);
+       if (np) {
+               sharp->backlight = of_find_backlight_by_node(np);
+               of_node_put(np);
+
+               if (!sharp->backlight)
+                       return -EPROBE_DEFER;
+       }
+
+       drm_panel_init(&sharp->base);
+       sharp->base.funcs = &sharp_panel_funcs;
+       sharp->base.dev = &sharp->link1->dev;
+
+       err = drm_panel_add(&sharp->base);
+       if (err < 0)
+               goto put_backlight;
+
+       return 0;
+
+put_backlight:
+       if (sharp->backlight)
+               put_device(&sharp->backlight->dev);
+
+       return err;
+}
+
+static void sharp_panel_del(struct sharp_panel *sharp)
+{
+       if (sharp->base.dev)
+               drm_panel_remove(&sharp->base);
+
+       if (sharp->backlight)
+               put_device(&sharp->backlight->dev);
+
+       if (sharp->link2)
+               put_device(&sharp->link2->dev);
+}
+
+static int sharp_panel_probe(struct mipi_dsi_device *dsi)
+{
+       struct mipi_dsi_device *secondary = NULL;
+       struct sharp_panel *sharp;
+       struct device_node *np;
+       int err;
+
+       dsi->lanes = 4;
+       dsi->format = MIPI_DSI_FMT_RGB888;
+       dsi->mode_flags = MIPI_DSI_MODE_LPM;
+
+       /* Find DSI-LINK1 */
+       np = of_parse_phandle(dsi->dev.of_node, "link2", 0);
+       if (np) {
+               secondary = of_find_mipi_dsi_device_by_node(np);
+               of_node_put(np);
+
+               if (!secondary)
+                       return -EPROBE_DEFER;
+       }
+
+       /* register a panel for only the DSI-LINK1 interface */
+       if (secondary) {
+               sharp = devm_kzalloc(&dsi->dev, sizeof(*sharp), GFP_KERNEL);
+               if (!sharp) {
+                       put_device(&secondary->dev);
+                       return -ENOMEM;
+               }
+
+               mipi_dsi_set_drvdata(dsi, sharp);
+
+               sharp->link2 = secondary;
+               sharp->link1 = dsi;
+
+               err = sharp_panel_add(sharp);
+               if (err < 0) {
+                       put_device(&secondary->dev);
+                       return err;
+               }
+       }
+
+       err = mipi_dsi_attach(dsi);
+       if (err < 0) {
+               if (secondary)
+                       sharp_panel_del(sharp);
+
+               return err;
+       }
+
+       return 0;
+}
+
+static int sharp_panel_remove(struct mipi_dsi_device *dsi)
+{
+       struct sharp_panel *sharp = mipi_dsi_get_drvdata(dsi);
+       int err;
+
+       /* only detach from host for the DSI-LINK2 interface */
+       if (!sharp) {
+               mipi_dsi_detach(dsi);
+               return 0;
+       }
+
+       err = sharp_panel_disable(&sharp->base);
+       if (err < 0)
+               dev_err(&dsi->dev, "failed to disable panel: %d\n", err);
+
+       err = mipi_dsi_detach(dsi);
+       if (err < 0)
+               dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
+
+       drm_panel_detach(&sharp->base);
+       sharp_panel_del(sharp);
+
+       return 0;
+}
+
+static void sharp_panel_shutdown(struct mipi_dsi_device *dsi)
+{
+       struct sharp_panel *sharp = mipi_dsi_get_drvdata(dsi);
+
+       /* nothing to do for DSI-LINK2 */
+       if (!sharp)
+               return;
+
+       sharp_panel_disable(&sharp->base);
+}
+
+static struct mipi_dsi_driver sharp_panel_driver = {
+       .driver = {
+               .name = "panel-sharp-lq101r1sx01",
+               .of_match_table = sharp_of_match,
+       },
+       .probe = sharp_panel_probe,
+       .remove = sharp_panel_remove,
+       .shutdown = sharp_panel_shutdown,
+};
+module_mipi_dsi_driver(sharp_panel_driver);
+
+MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
+MODULE_DESCRIPTION("Sharp LQ101R1SX01 panel driver");
+MODULE_LICENSE("GPL v2");
index 23de22f8c82078a11a4c9a7815c8aa099d74ddf9..c4b6167a8bf33c0189bc83ea298653d2d95fcb2b 100644 (file)
@@ -247,21 +247,14 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
        if (IS_ERR(panel->supply))
                return PTR_ERR(panel->supply);
 
-       panel->enable_gpio = devm_gpiod_get_optional(dev, "enable");
+       panel->enable_gpio = devm_gpiod_get_optional(dev, "enable",
+                                                    GPIOD_OUT_LOW);
        if (IS_ERR(panel->enable_gpio)) {
                err = PTR_ERR(panel->enable_gpio);
                dev_err(dev, "failed to request GPIO: %d\n", err);
                return err;
        }
 
-       if (panel->enable_gpio) {
-               err = gpiod_direction_output(panel->enable_gpio, 0);
-               if (err < 0) {
-                       dev_err(dev, "failed to setup GPIO: %d\n", err);
-                       return err;
-               }
-       }
-
        backlight = of_parse_phandle(dev->of_node, "backlight", 0);
        if (backlight) {
                panel->backlight = of_find_backlight_by_node(backlight);
@@ -376,6 +369,29 @@ static const struct panel_desc auo_b101xtn01 = {
        },
 };
 
+static const struct drm_display_mode auo_b116xw03_mode = {
+       .clock = 70589,
+       .hdisplay = 1366,
+       .hsync_start = 1366 + 40,
+       .hsync_end = 1366 + 40 + 40,
+       .htotal = 1366 + 40 + 40 + 32,
+       .vdisplay = 768,
+       .vsync_start = 768 + 10,
+       .vsync_end = 768 + 10 + 12,
+       .vtotal = 768 + 10 + 12 + 6,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc auo_b116xw03 = {
+       .modes = &auo_b116xw03_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 256,
+               .height = 144,
+       },
+};
+
 static const struct drm_display_mode auo_b133xtn01_mode = {
        .clock = 69500,
        .hdisplay = 1366,
@@ -415,6 +431,7 @@ static const struct drm_display_mode auo_b133htn01_mode = {
 static const struct panel_desc auo_b133htn01 = {
        .modes = &auo_b133htn01_mode,
        .num_modes = 1,
+       .bpc = 6,
        .size = {
                .width = 293,
                .height = 165,
@@ -536,22 +553,92 @@ static const struct drm_display_mode foxlink_fl500wvr00_a0t_mode = {
 static const struct panel_desc foxlink_fl500wvr00_a0t = {
        .modes = &foxlink_fl500wvr00_a0t_mode,
        .num_modes = 1,
+       .bpc = 8,
        .size = {
                .width = 108,
                .height = 65,
        },
 };
 
-static const struct drm_display_mode innolux_n116bge_mode = {
+static const struct drm_display_mode hannstar_hsd070pww1_mode = {
+       .clock = 71100,
+       .hdisplay = 1280,
+       .hsync_start = 1280 + 1,
+       .hsync_end = 1280 + 1 + 158,
+       .htotal = 1280 + 1 + 158 + 1,
+       .vdisplay = 800,
+       .vsync_start = 800 + 1,
+       .vsync_end = 800 + 1 + 21,
+       .vtotal = 800 + 1 + 21 + 1,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc hannstar_hsd070pww1 = {
+       .modes = &hannstar_hsd070pww1_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 151,
+               .height = 94,
+       },
+};
+
+static const struct drm_display_mode hitachi_tx23d38vm0caa_mode = {
+       .clock = 33333,
+       .hdisplay = 800,
+       .hsync_start = 800 + 85,
+       .hsync_end = 800 + 85 + 86,
+       .htotal = 800 + 85 + 86 + 85,
+       .vdisplay = 480,
+       .vsync_start = 480 + 16,
+       .vsync_end = 480 + 16 + 13,
+       .vtotal = 480 + 16 + 13 + 16,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc hitachi_tx23d38vm0caa = {
+       .modes = &hitachi_tx23d38vm0caa_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 195,
+               .height = 117,
+       },
+};
+
+static const struct drm_display_mode innolux_g121i1_l01_mode = {
        .clock = 71000,
+       .hdisplay = 1280,
+       .hsync_start = 1280 + 64,
+       .hsync_end = 1280 + 64 + 32,
+       .htotal = 1280 + 64 + 32 + 64,
+       .vdisplay = 800,
+       .vsync_start = 800 + 9,
+       .vsync_end = 800 + 9 + 6,
+       .vtotal = 800 + 9 + 6 + 9,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc innolux_g121i1_l01 = {
+       .modes = &innolux_g121i1_l01_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 261,
+               .height = 163,
+       },
+};
+
+static const struct drm_display_mode innolux_n116bge_mode = {
+       .clock = 76420,
        .hdisplay = 1366,
-       .hsync_start = 1366 + 64,
-       .hsync_end = 1366 + 64 + 6,
-       .htotal = 1366 + 64 + 6 + 64,
+       .hsync_start = 1366 + 136,
+       .hsync_end = 1366 + 136 + 30,
+       .htotal = 1366 + 136 + 30 + 60,
        .vdisplay = 768,
        .vsync_start = 768 + 8,
-       .vsync_end = 768 + 8 + 4,
-       .vtotal = 768 + 8 + 4 + 8,
+       .vsync_end = 768 + 8 + 12,
+       .vtotal = 768 + 8 + 12 + 12,
        .vrefresh = 60,
        .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
 };
@@ -642,6 +729,9 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "auo,b101xtn01",
                .data = &auo_b101xtn01,
+       }, {
+               .compatible = "auo,b116xw03",
+               .data = &auo_b116xw03,
        }, {
                .compatible = "auo,b133htn01",
                .data = &auo_b133htn01,
@@ -666,6 +756,15 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "foxlink,fl500wvr00-a0t",
                .data = &foxlink_fl500wvr00_a0t,
+       }, {
+               .compatible = "hannstar,hsd070pww1",
+               .data = &hannstar_hsd070pww1,
+       }, {
+               .compatible = "hit,tx23d38vm0caa",
+               .data = &hitachi_tx23d38vm0caa
+       }, {
+               .compatible ="innolux,g121i1-l01",
+               .data = &innolux_g121i1_l01
        }, {
                .compatible = "innolux,n116bge",
                .data = &innolux_n116bge,
@@ -741,6 +840,7 @@ static const struct panel_desc_dsi lg_ld070wx3_sl01 = {
        .desc = {
                .modes = &lg_ld070wx3_sl01_mode,
                .num_modes = 1,
+               .bpc = 8,
                .size = {
                        .width = 94,
                        .height = 151,
@@ -768,6 +868,7 @@ static const struct panel_desc_dsi lg_lh500wx1_sd03 = {
        .desc = {
                .modes = &lg_lh500wx1_sd03_mode,
                .num_modes = 1,
+               .bpc = 8,
                .size = {
                        .width = 62,
                        .height = 110,
@@ -795,6 +896,7 @@ static const struct panel_desc_dsi panasonic_vvx10f004b00 = {
        .desc = {
                .modes = &panasonic_vvx10f004b00_mode,
                .num_modes = 1,
+               .bpc = 8,
                .size = {
                        .width = 217,
                        .height = 136,
@@ -864,7 +966,6 @@ static void panel_simple_dsi_shutdown(struct mipi_dsi_device *dsi)
 static struct mipi_dsi_driver panel_simple_dsi_driver = {
        .driver = {
                .name = "panel-simple-dsi",
-               .owner = THIS_MODULE,
                .of_match_table = dsi_of_match,
        },
        .probe = panel_simple_dsi_probe,
index 8b7892880ad243c11e76eb49a6489aa626a4b6f1..4a0a8b29b0a1e070ab0ce4e7574def7a73ab7383 100644 (file)
@@ -101,14 +101,37 @@ static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev)
        return 0;
 }
 
+static void qxl_update_offset_props(struct qxl_device *qdev)
+{
+       struct drm_device *dev = qdev->ddev;
+       struct drm_connector *connector;
+       struct qxl_output *output;
+       struct qxl_head *head;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               output = drm_connector_to_qxl_output(connector);
+
+               head = &qdev->client_monitors_config->heads[output->index];
+
+               drm_object_property_set_value(&connector->base,
+                       dev->mode_config.suggested_x_property, head->x);
+               drm_object_property_set_value(&connector->base,
+                       dev->mode_config.suggested_y_property, head->y);
+       }
+}
+
 void qxl_display_read_client_monitors_config(struct qxl_device *qdev)
 {
 
+       struct drm_device *dev = qdev->ddev;
        while (qxl_display_copy_rom_client_monitors_config(qdev)) {
                qxl_io_log(qdev, "failed crc check for client_monitors_config,"
                                 " retrying\n");
        }
 
+       drm_modeset_lock_all(dev);
+       qxl_update_offset_props(qdev);
+       drm_modeset_unlock_all(dev);
        if (!drm_helper_hpd_irq_event(qdev->ddev)) {
                /* notify that the monitor configuration changed, to
                   adjust at the arbitrary resolution */
@@ -569,7 +592,6 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        struct qxl_device *qdev = dev->dev_private;
-       struct qxl_mode *m = (void *)mode->private;
        struct qxl_framebuffer *qfb;
        struct qxl_bo *bo, *old_bo = NULL;
        struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
@@ -587,12 +609,6 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
        }
        qfb = to_qxl_framebuffer(crtc->primary->fb);
        bo = gem_to_qxl_bo(qfb->obj);
-       if (!m)
-               /* and do we care? */
-               DRM_DEBUG("%dx%d: not a native mode\n", x, y);
-       else
-               DRM_DEBUG("%dx%d: qxl id %d\n",
-                         mode->hdisplay, mode->vdisplay, m->id);
        DRM_DEBUG("+%d+%d (%d,%d) => (%d,%d)\n",
                  x, y,
                  mode->hdisplay, mode->vdisplay,
@@ -952,6 +968,10 @@ static int qdev_output_init(struct drm_device *dev, int num_output)
 
        drm_object_attach_property(&connector->base,
                                   qdev->hotplug_mode_update_property, 0);
+       drm_object_attach_property(&connector->base,
+                                  dev->mode_config.suggested_x_property, 0);
+       drm_object_attach_property(&connector->base,
+                                  dev->mode_config.suggested_y_property, 0);
        drm_connector_register(connector);
        return 0;
 }
@@ -1065,6 +1085,7 @@ int qxl_modeset_init(struct qxl_device *qdev)
 
        qdev->ddev->mode_config.fb_base = qdev->vram_base;
 
+       drm_mode_create_suggested_offset_properties(qdev->ddev);
        qxl_mode_create_hotplug_mode_update_property(qdev);
 
        for (i = 0 ; i < qxl_num_crtc; ++i) {
index 575e986f82a76239113e2e122b42ce961a24e3e0..8fd2d9f58f770a3de4b7fc2b840b1e788c5aafdb 100644 (file)
@@ -905,7 +905,7 @@ static int r128_cce_dispatch_write_span(struct drm_device *dev,
        if (IS_ERR(buffer))
                return PTR_ERR(buffer);
 
-       mask_size = depth->n * sizeof(u8);
+       mask_size = depth->n;
        if (depth->mask) {
                mask = memdup_user(depth->mask, mask_size);
                if (IS_ERR(mask)) {
@@ -1010,7 +1010,7 @@ static int r128_cce_dispatch_write_pixels(struct drm_device *dev,
        }
 
        if (depth->mask) {
-               mask_size = depth->n * sizeof(u8);
+               mask_size = depth->n;
                mask = memdup_user(depth->mask, mask_size);
                if (IS_ERR(mask)) {
                        kfree(x);
index d01b87991422588c24b8f477a1050641cb683aa1..12bc21219a0ea13f305133139ba9a4afe9dcf618 100644 (file)
@@ -80,7 +80,8 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
        r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \
        rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \
        trinity_smc.o ni_dpm.o si_smc.o si_dpm.o kv_smc.o kv_dpm.o ci_smc.o \
-       ci_dpm.o dce6_afmt.o radeon_vm.o radeon_ucode.o radeon_ib.o radeon_mn.o
+       ci_dpm.o dce6_afmt.o radeon_vm.o radeon_ucode.o radeon_ib.o radeon_mn.o \
+       radeon_sync.o
 
 # add async DMA block
 radeon-y += \
@@ -104,6 +105,7 @@ radeon-y += \
        radeon_vce.o \
        vce_v1_0.o \
        vce_v2_0.o \
+       radeon_kfd.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
index 11a55e9dad7fef5d04ae838a6b7ae2c2f6b04958..3f898d020ae691f9bc38b482fec6a77a05a44843 100644 (file)
 static const struct ci_pt_defaults defaults_hawaii_xt =
 {
        1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0xB0000,
-       { 0x84,  0x0,   0x0,   0x7F,  0x0,   0x0,   0x5A,  0x60,  0x51,  0x8E,  0x79,  0x6B,  0x5F,  0x90,  0x79  },
-       { 0x1EA, 0x1EA, 0x1EA, 0x224, 0x224, 0x224, 0x24F, 0x24F, 0x24F, 0x28E, 0x28E, 0x28E, 0x2BC, 0x2BC, 0x2BC }
+       { 0x2E,  0x00,  0x00,  0x88,  0x00,  0x00,  0x72,  0x60,  0x51,  0xA7,  0x79,  0x6B,  0x90,  0xBD,  0x79  },
+       { 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 }
 };
 
 static const struct ci_pt_defaults defaults_hawaii_pro =
 {
        1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0x65062,
-       { 0x93,  0x0,   0x0,   0x97,  0x0,   0x0,   0x6B,  0x60,  0x51,  0x95,  0x79,  0x6B,  0x5F,  0x90,  0x79  },
-       { 0x1EA, 0x1EA, 0x1EA, 0x224, 0x224, 0x224, 0x24F, 0x24F, 0x24F, 0x28E, 0x28E, 0x28E, 0x2BC, 0x2BC, 0x2BC }
+       { 0x2E,  0x00,  0x00,  0x88,  0x00,  0x00,  0x72,  0x60,  0x51,  0xA7,  0x79,  0x6B,  0x90,  0xBD,  0x79  },
+       { 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 }
 };
 
 static const struct ci_pt_defaults defaults_bonaire_xt =
@@ -184,6 +184,9 @@ static int ci_set_overdrive_target_tdp(struct radeon_device *rdev,
                                       u32 target_tdp);
 static int ci_update_uvd_dpm(struct radeon_device *rdev, bool gate);
 
+static PPSMC_Result ci_send_msg_to_smc_with_parameter(struct radeon_device *rdev,
+                                                     PPSMC_Msg msg, u32 parameter);
+
 static struct ci_power_info *ci_get_pi(struct radeon_device *rdev)
 {
         struct ci_power_info *pi = rdev->pm.dpm.priv;
@@ -249,7 +252,10 @@ static void ci_initialize_powertune_defaults(struct radeon_device *rdev)
 
        if (pi->caps_power_containment) {
                pi->caps_cac = true;
-               pi->enable_bapm_feature = true;
+               if (rdev->family == CHIP_HAWAII)
+                       pi->enable_bapm_feature = false;
+               else
+                       pi->enable_bapm_feature = true;
                pi->enable_tdc_limit_feature = true;
                pi->enable_pkg_pwr_tracking_feature = true;
        }
@@ -352,6 +358,21 @@ static int ci_populate_dw8(struct radeon_device *rdev)
        return 0;
 }
 
+static int ci_populate_fuzzy_fan(struct radeon_device *rdev)
+{
+       struct ci_power_info *pi = ci_get_pi(rdev);
+
+       if ((rdev->pm.dpm.fan.fan_output_sensitivity & (1 << 15)) ||
+           (rdev->pm.dpm.fan.fan_output_sensitivity == 0))
+               rdev->pm.dpm.fan.fan_output_sensitivity =
+                       rdev->pm.dpm.fan.default_fan_output_sensitivity;
+
+       pi->smc_powertune_table.FuzzyFan_PwmSetDelta =
+               cpu_to_be16(rdev->pm.dpm.fan.fan_output_sensitivity);
+
+       return 0;
+}
+
 static int ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(struct radeon_device *rdev)
 {
        struct ci_power_info *pi = ci_get_pi(rdev);
@@ -475,6 +496,9 @@ static int ci_populate_pm_base(struct radeon_device *rdev)
                if (ret)
                        return ret;
                ret = ci_populate_dw8(rdev);
+               if (ret)
+                       return ret;
+               ret = ci_populate_fuzzy_fan(rdev);
                if (ret)
                        return ret;
                ret = ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(rdev);
@@ -690,6 +714,25 @@ static int ci_enable_smc_cac(struct radeon_device *rdev, bool enable)
        return ret;
 }
 
+static int ci_enable_thermal_based_sclk_dpm(struct radeon_device *rdev,
+                                           bool enable)
+{
+       struct ci_power_info *pi = ci_get_pi(rdev);
+       PPSMC_Result smc_result = PPSMC_Result_OK;
+
+       if (pi->thermal_sclk_dpm_enabled) {
+               if (enable)
+                       smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_ENABLE_THERMAL_DPM);
+               else
+                       smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_DISABLE_THERMAL_DPM);
+       }
+
+       if (smc_result == PPSMC_Result_OK)
+               return 0;
+       else
+               return -EINVAL;
+}
+
 static int ci_power_control_set_level(struct radeon_device *rdev)
 {
        struct ci_power_info *pi = ci_get_pi(rdev);
@@ -700,13 +743,11 @@ static int ci_power_control_set_level(struct radeon_device *rdev)
        int ret = 0;
        bool adjust_polarity = false; /* ??? */
 
-       if (pi->caps_power_containment &&
-           (pi->power_containment_features & POWERCONTAINMENT_FEATURE_BAPM)) {
+       if (pi->caps_power_containment) {
                adjust_percent = adjust_polarity ?
                        rdev->pm.dpm.tdp_adjustment : (-1 * rdev->pm.dpm.tdp_adjustment);
                target_tdp = ((100 + adjust_percent) *
                              (s32)cac_tdp_table->configurable_tdp) / 100;
-               target_tdp *= 256;
 
                ret = ci_set_overdrive_target_tdp(rdev, (u32)target_tdp);
        }
@@ -814,7 +855,7 @@ static void ci_apply_state_adjust_rules(struct radeon_device *rdev,
        }
 }
 
-static int ci_set_thermal_temperature_range(struct radeon_device *rdev,
+static int ci_thermal_set_temperature_range(struct radeon_device *rdev,
                                            int min_temp, int max_temp)
 {
        int low_temp = 0 * 1000;
@@ -850,6 +891,350 @@ static int ci_set_thermal_temperature_range(struct radeon_device *rdev,
        return 0;
 }
 
+static int ci_thermal_enable_alert(struct radeon_device *rdev,
+                                  bool enable)
+{
+       u32 thermal_int = RREG32_SMC(CG_THERMAL_INT);
+       PPSMC_Result result;
+
+       if (enable) {
+               thermal_int &= ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
+               WREG32_SMC(CG_THERMAL_INT, thermal_int);
+               rdev->irq.dpm_thermal = false;
+               result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Thermal_Cntl_Enable);
+               if (result != PPSMC_Result_OK) {
+                       DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
+                       return -EINVAL;
+               }
+       } else {
+               thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
+               WREG32_SMC(CG_THERMAL_INT, thermal_int);
+               rdev->irq.dpm_thermal = true;
+               result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Thermal_Cntl_Disable);
+               if (result != PPSMC_Result_OK) {
+                       DRM_DEBUG_KMS("Could not disable thermal interrupts.\n");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static void ci_fan_ctrl_set_static_mode(struct radeon_device *rdev, u32 mode)
+{
+       struct ci_power_info *pi = ci_get_pi(rdev);
+       u32 tmp;
+
+       if (pi->fan_ctrl_is_in_default_mode) {
+               tmp = (RREG32_SMC(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK) >> FDO_PWM_MODE_SHIFT;
+               pi->fan_ctrl_default_mode = tmp;
+               tmp = (RREG32_SMC(CG_FDO_CTRL2) & TMIN_MASK) >> TMIN_SHIFT;
+               pi->t_min = tmp;
+               pi->fan_ctrl_is_in_default_mode = false;
+       }
+
+       tmp = RREG32_SMC(CG_FDO_CTRL2) & ~TMIN_MASK;
+       tmp |= TMIN(0);
+       WREG32_SMC(CG_FDO_CTRL2, tmp);
+
+       tmp = RREG32_SMC(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK;
+       tmp |= FDO_PWM_MODE(mode);
+       WREG32_SMC(CG_FDO_CTRL2, tmp);
+}
+
+static int ci_thermal_setup_fan_table(struct radeon_device *rdev)
+{
+       struct ci_power_info *pi = ci_get_pi(rdev);
+       SMU7_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
+       u32 duty100;
+       u32 t_diff1, t_diff2, pwm_diff1, pwm_diff2;
+       u16 fdo_min, slope1, slope2;
+       u32 reference_clock, tmp;
+       int ret;
+       u64 tmp64;
+
+       if (!pi->fan_table_start) {
+               rdev->pm.dpm.fan.ucode_fan_control = false;
+               return 0;
+       }
+
+       duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
+
+       if (duty100 == 0) {
+               rdev->pm.dpm.fan.ucode_fan_control = false;
+               return 0;
+       }
+
+       tmp64 = (u64)rdev->pm.dpm.fan.pwm_min * duty100;
+       do_div(tmp64, 10000);
+       fdo_min = (u16)tmp64;
+
+       t_diff1 = rdev->pm.dpm.fan.t_med - rdev->pm.dpm.fan.t_min;
+       t_diff2 = rdev->pm.dpm.fan.t_high - rdev->pm.dpm.fan.t_med;
+
+       pwm_diff1 = rdev->pm.dpm.fan.pwm_med - rdev->pm.dpm.fan.pwm_min;
+       pwm_diff2 = rdev->pm.dpm.fan.pwm_high - rdev->pm.dpm.fan.pwm_med;
+
+       slope1 = (u16)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
+       slope2 = (u16)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
+
+       fan_table.TempMin = cpu_to_be16((50 + rdev->pm.dpm.fan.t_min) / 100);
+       fan_table.TempMed = cpu_to_be16((50 + rdev->pm.dpm.fan.t_med) / 100);
+       fan_table.TempMax = cpu_to_be16((50 + rdev->pm.dpm.fan.t_max) / 100);
+
+       fan_table.Slope1 = cpu_to_be16(slope1);
+       fan_table.Slope2 = cpu_to_be16(slope2);
+
+       fan_table.FdoMin = cpu_to_be16(fdo_min);
+
+       fan_table.HystDown = cpu_to_be16(rdev->pm.dpm.fan.t_hyst);
+
+       fan_table.HystUp = cpu_to_be16(1);
+
+       fan_table.HystSlope = cpu_to_be16(1);
+
+       fan_table.TempRespLim = cpu_to_be16(5);
+
+       reference_clock = radeon_get_xclk(rdev);
+
+       fan_table.RefreshPeriod = cpu_to_be32((rdev->pm.dpm.fan.cycle_delay *
+                                              reference_clock) / 1600);
+
+       fan_table.FdoMax = cpu_to_be16((u16)duty100);
+
+       tmp = (RREG32_SMC(CG_MULT_THERMAL_CTRL) & TEMP_SEL_MASK) >> TEMP_SEL_SHIFT;
+       fan_table.TempSrc = (uint8_t)tmp;
+
+       ret = ci_copy_bytes_to_smc(rdev,
+                                  pi->fan_table_start,
+                                  (u8 *)(&fan_table),
+                                  sizeof(fan_table),
+                                  pi->sram_end);
+
+       if (ret) {
+               DRM_ERROR("Failed to load fan table to the SMC.");
+               rdev->pm.dpm.fan.ucode_fan_control = false;
+       }
+
+       return 0;
+}
+
+static int ci_fan_ctrl_start_smc_fan_control(struct radeon_device *rdev)
+{
+       struct ci_power_info *pi = ci_get_pi(rdev);
+       PPSMC_Result ret;
+
+       if (pi->caps_od_fuzzy_fan_control_support) {
+               ret = ci_send_msg_to_smc_with_parameter(rdev,
+                                                       PPSMC_StartFanControl,
+                                                       FAN_CONTROL_FUZZY);
+               if (ret != PPSMC_Result_OK)
+                       return -EINVAL;
+               ret = ci_send_msg_to_smc_with_parameter(rdev,
+                                                       PPSMC_MSG_SetFanPwmMax,
+                                                       rdev->pm.dpm.fan.default_max_fan_pwm);
+               if (ret != PPSMC_Result_OK)
+                       return -EINVAL;
+       } else {
+               ret = ci_send_msg_to_smc_with_parameter(rdev,
+                                                       PPSMC_StartFanControl,
+                                                       FAN_CONTROL_TABLE);
+               if (ret != PPSMC_Result_OK)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+#if 0
+static int ci_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev)
+{
+       PPSMC_Result ret;
+
+       ret = ci_send_msg_to_smc(rdev, PPSMC_StopFanControl);
+       if (ret == PPSMC_Result_OK)
+               return 0;
+       else
+               return -EINVAL;
+}
+
+static int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
+                                            u32 *speed)
+{
+       u32 duty, duty100;
+       u64 tmp64;
+
+       if (rdev->pm.no_fan)
+               return -ENOENT;
+
+       duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
+       duty = (RREG32_SMC(CG_THERMAL_STATUS) & FDO_PWM_DUTY_MASK) >> FDO_PWM_DUTY_SHIFT;
+
+       if (duty100 == 0)
+               return -EINVAL;
+
+       tmp64 = (u64)duty * 100;
+       do_div(tmp64, duty100);
+       *speed = (u32)tmp64;
+
+       if (*speed > 100)
+               *speed = 100;
+
+       return 0;
+}
+
+static int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
+                                            u32 speed)
+{
+       u32 tmp;
+       u32 duty, duty100;
+       u64 tmp64;
+
+       if (rdev->pm.no_fan)
+               return -ENOENT;
+
+       if (speed > 100)
+               return -EINVAL;
+
+       if (rdev->pm.dpm.fan.ucode_fan_control)
+               ci_fan_ctrl_stop_smc_fan_control(rdev);
+
+       duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
+
+       if (duty100 == 0)
+               return -EINVAL;
+
+       tmp64 = (u64)speed * duty100;
+       do_div(tmp64, 100);
+       duty = (u32)tmp64;
+
+       tmp = RREG32_SMC(CG_FDO_CTRL0) & ~FDO_STATIC_DUTY_MASK;
+       tmp |= FDO_STATIC_DUTY(duty);
+       WREG32_SMC(CG_FDO_CTRL0, tmp);
+
+       ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
+
+       return 0;
+}
+
+static int ci_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev,
+                                        u32 *speed)
+{
+       u32 tach_period;
+       u32 xclk = radeon_get_xclk(rdev);
+
+       if (rdev->pm.no_fan)
+               return -ENOENT;
+
+       if (rdev->pm.fan_pulses_per_revolution == 0)
+               return -ENOENT;
+
+       tach_period = (RREG32_SMC(CG_TACH_STATUS) & TACH_PERIOD_MASK) >> TACH_PERIOD_SHIFT;
+       if (tach_period == 0)
+               return -ENOENT;
+
+       *speed = 60 * xclk * 10000 / tach_period;
+
+       return 0;
+}
+
+static int ci_fan_ctrl_set_fan_speed_rpm(struct radeon_device *rdev,
+                                        u32 speed)
+{
+       u32 tach_period, tmp;
+       u32 xclk = radeon_get_xclk(rdev);
+
+       if (rdev->pm.no_fan)
+               return -ENOENT;
+
+       if (rdev->pm.fan_pulses_per_revolution == 0)
+               return -ENOENT;
+
+       if ((speed < rdev->pm.fan_min_rpm) ||
+           (speed > rdev->pm.fan_max_rpm))
+               return -EINVAL;
+
+       if (rdev->pm.dpm.fan.ucode_fan_control)
+               ci_fan_ctrl_stop_smc_fan_control(rdev);
+
+       tach_period = 60 * xclk * 10000 / (8 * speed);
+       tmp = RREG32_SMC(CG_TACH_CTRL) & ~TARGET_PERIOD_MASK;
+       tmp |= TARGET_PERIOD(tach_period);
+       WREG32_SMC(CG_TACH_CTRL, tmp);
+
+       ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
+
+       return 0;
+}
+#endif
+
+static void ci_fan_ctrl_set_default_mode(struct radeon_device *rdev)
+{
+       struct ci_power_info *pi = ci_get_pi(rdev);
+       u32 tmp;
+
+       if (!pi->fan_ctrl_is_in_default_mode) {
+               tmp = RREG32_SMC(CG_FDO_CTRL2) & ~FDO_PWM_MODE_MASK;
+               tmp |= FDO_PWM_MODE(pi->fan_ctrl_default_mode);
+               WREG32_SMC(CG_FDO_CTRL2, tmp);
+
+               tmp = RREG32_SMC(CG_FDO_CTRL2) & TMIN_MASK;
+               tmp |= TMIN(pi->t_min);
+               WREG32_SMC(CG_FDO_CTRL2, tmp);
+               pi->fan_ctrl_is_in_default_mode = true;
+       }
+}
+
+static void ci_thermal_start_smc_fan_control(struct radeon_device *rdev)
+{
+       if (rdev->pm.dpm.fan.ucode_fan_control) {
+               ci_fan_ctrl_start_smc_fan_control(rdev);
+               ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
+       }
+}
+
+static void ci_thermal_initialize(struct radeon_device *rdev)
+{
+       u32 tmp;
+
+       if (rdev->pm.fan_pulses_per_revolution) {
+               tmp = RREG32_SMC(CG_TACH_CTRL) & ~EDGE_PER_REV_MASK;
+               tmp |= EDGE_PER_REV(rdev->pm.fan_pulses_per_revolution -1);
+               WREG32_SMC(CG_TACH_CTRL, tmp);
+       }
+
+       tmp = RREG32_SMC(CG_FDO_CTRL2) & ~TACH_PWM_RESP_RATE_MASK;
+       tmp |= TACH_PWM_RESP_RATE(0x28);
+       WREG32_SMC(CG_FDO_CTRL2, tmp);
+}
+
+static int ci_thermal_start_thermal_controller(struct radeon_device *rdev)
+{
+       int ret;
+
+       ci_thermal_initialize(rdev);
+       ret = ci_thermal_set_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+       if (ret)
+               return ret;
+       ret = ci_thermal_enable_alert(rdev, true);
+       if (ret)
+               return ret;
+       if (rdev->pm.dpm.fan.ucode_fan_control) {
+               ret = ci_thermal_setup_fan_table(rdev);
+               if (ret)
+                       return ret;
+               ci_thermal_start_smc_fan_control(rdev);
+       }
+
+       return 0;
+}
+
+static void ci_thermal_stop_thermal_controller(struct radeon_device *rdev)
+{
+       if (!rdev->pm.no_fan)
+               ci_fan_ctrl_set_default_mode(rdev);
+}
+
 #if 0
 static int ci_read_smc_soft_register(struct radeon_device *rdev,
                                     u16 reg_offset, u32 *value)
@@ -1253,7 +1638,7 @@ static int ci_dpm_force_state_sclk(struct radeon_device *rdev, u32 n)
 
        if (!pi->sclk_dpm_key_disabled) {
                PPSMC_Result smc_result =
-                       ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, n);
+                       ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SCLKDPM_SetEnabledMask, 1 << n);
                if (smc_result != PPSMC_Result_OK)
                        return -EINVAL;
        }
@@ -1267,7 +1652,7 @@ static int ci_dpm_force_state_mclk(struct radeon_device *rdev, u32 n)
 
        if (!pi->mclk_dpm_key_disabled) {
                PPSMC_Result smc_result =
-                       ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_MCLKDPM_ForceState, n);
+                       ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_MCLKDPM_SetEnabledMask, 1 << n);
                if (smc_result != PPSMC_Result_OK)
                        return -EINVAL;
        }
@@ -2042,6 +2427,33 @@ static int ci_force_switch_to_arb_f0(struct radeon_device *rdev)
        return ni_copy_and_switch_arb_sets(rdev, tmp, MC_CG_ARB_FREQ_F0);
 }
 
+static void ci_register_patching_mc_arb(struct radeon_device *rdev,
+                                       const u32 engine_clock,
+                                       const u32 memory_clock,
+                                       u32 *dram_timimg2)
+{
+       bool patch;
+       u32 tmp, tmp2;
+
+       tmp = RREG32(MC_SEQ_MISC0);
+       patch = ((tmp & 0x0000f00) == 0x300) ? true : false;
+
+       if (patch &&
+           ((rdev->pdev->device == 0x67B0) ||
+            (rdev->pdev->device == 0x67B1))) {
+               if ((memory_clock > 100000) && (memory_clock <= 125000)) {
+                       tmp2 = (((0x31 * engine_clock) / 125000) - 1) & 0xff;
+                       *dram_timimg2 &= ~0x00ff0000;
+                       *dram_timimg2 |= tmp2 << 16;
+               } else if ((memory_clock > 125000) && (memory_clock <= 137500)) {
+                       tmp2 = (((0x36 * engine_clock) / 137500) - 1) & 0xff;
+                       *dram_timimg2 &= ~0x00ff0000;
+                       *dram_timimg2 |= tmp2 << 16;
+               }
+       }
+}
+
+
 static int ci_populate_memory_timing_parameters(struct radeon_device *rdev,
                                                u32 sclk,
                                                u32 mclk,
@@ -2057,6 +2469,8 @@ static int ci_populate_memory_timing_parameters(struct radeon_device *rdev,
        dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
        burst_time = RREG32(MC_ARB_BURST_TIME) & STATE0_MASK;
 
+       ci_register_patching_mc_arb(rdev, sclk, mclk, &dram_timing2);
+
        arb_regs->McArbDramTiming  = cpu_to_be32(dram_timing);
        arb_regs->McArbDramTiming2 = cpu_to_be32(dram_timing2);
        arb_regs->McArbBurstTime = (u8)burst_time;
@@ -2351,10 +2765,10 @@ static int ci_calculate_mclk_params(struct radeon_device *rdev,
                u32 tmp;
                u32 reference_clock = rdev->clock.mpll.reference_freq;
 
-               if (pi->mem_gddr5)
-                       freq_nom = memory_clock * 4;
+               if (mpll_param.qdr == 1)
+                       freq_nom = memory_clock * 4 * (1 << mpll_param.post_div);
                else
-                       freq_nom = memory_clock * 2;
+                       freq_nom = memory_clock * 2 * (1 << mpll_param.post_div);
 
                tmp = (freq_nom / reference_clock);
                tmp = tmp * tmp;
@@ -2434,7 +2848,6 @@ static int ci_populate_single_memory_level(struct radeon_device *rdev,
                                                      &memory_level->MinVddcPhases);
 
        memory_level->EnabledForThrottle = 1;
-       memory_level->EnabledForActivity = 1;
        memory_level->UpH = 0;
        memory_level->DownH = 100;
        memory_level->VoltageDownH = 0;
@@ -2767,7 +3180,6 @@ static int ci_populate_single_graphic_level(struct radeon_device *rdev,
 
        graphic_level->CcPwrDynRm = 0;
        graphic_level->CcPwrDynRm1 = 0;
-       graphic_level->EnabledForActivity = 1;
        graphic_level->EnabledForThrottle = 1;
        graphic_level->UpH = 0;
        graphic_level->DownH = 0;
@@ -2816,10 +3228,13 @@ static int ci_populate_all_graphic_levels(struct radeon_device *rdev)
                                                       &pi->smc_state_table.GraphicsLevel[i]);
                if (ret)
                        return ret;
+               if (i > 1)
+                       pi->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0;
                if (i == (dpm_table->sclk_table.count - 1))
                        pi->smc_state_table.GraphicsLevel[i].DisplayWatermark =
                                PPSMC_DISPLAY_WATERMARK_HIGH;
        }
+       pi->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1;
 
        pi->smc_state_table.GraphicsDpmLevelCount = (u8)dpm_table->sclk_table.count;
        pi->dpm_level_enable_mask.sclk_dpm_enable_mask =
@@ -2863,6 +3278,16 @@ static int ci_populate_all_memory_levels(struct radeon_device *rdev)
                        return ret;
        }
 
+       pi->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
+
+       if ((dpm_table->mclk_table.count >= 2) &&
+           ((rdev->pdev->device == 0x67B0) || (rdev->pdev->device == 0x67B1))) {
+               pi->smc_state_table.MemoryLevel[1].MinVddc =
+                       pi->smc_state_table.MemoryLevel[0].MinVddc;
+               pi->smc_state_table.MemoryLevel[1].MinVddcPhases =
+                       pi->smc_state_table.MemoryLevel[0].MinVddcPhases;
+       }
+
        pi->smc_state_table.MemoryLevel[0].ActivityLevel = cpu_to_be16(0x1F);
 
        pi->smc_state_table.MemoryDpmLevelCount = (u8)dpm_table->mclk_table.count;
@@ -2919,9 +3344,14 @@ static int ci_setup_default_pcie_tables(struct radeon_device *rdev)
                                  &pi->dpm_table.pcie_speed_table,
                                  SMU7_MAX_LEVELS_LINK);
 
-       ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 0,
-                                 pi->pcie_gen_powersaving.min,
-                                 pi->pcie_lane_powersaving.min);
+       if (rdev->family == CHIP_BONAIRE)
+               ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 0,
+                                         pi->pcie_gen_powersaving.min,
+                                         pi->pcie_lane_powersaving.max);
+       else
+               ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 0,
+                                         pi->pcie_gen_powersaving.min,
+                                         pi->pcie_lane_powersaving.min);
        ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 1,
                                  pi->pcie_gen_performance.min,
                                  pi->pcie_lane_performance.min);
@@ -2988,19 +3418,21 @@ static int ci_setup_default_dpm_tables(struct radeon_device *rdev)
                     allowed_sclk_vddc_table->entries[i].clk)) {
                        pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].value =
                                allowed_sclk_vddc_table->entries[i].clk;
-                       pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].enabled = true;
+                       pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].enabled =
+                               (i == 0) ? true : false;
                        pi->dpm_table.sclk_table.count++;
                }
        }
 
        pi->dpm_table.mclk_table.count = 0;
        for (i = 0; i < allowed_mclk_table->count; i++) {
-               if ((i==0) ||
+               if ((i == 0) ||
                    (pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count-1].value !=
                     allowed_mclk_table->entries[i].clk)) {
                        pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].value =
                                allowed_mclk_table->entries[i].clk;
-                       pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].enabled = true;
+                       pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].enabled =
+                               (i == 0) ? true : false;
                        pi->dpm_table.mclk_table.count++;
                }
        }
@@ -3166,7 +3598,7 @@ static int ci_init_smc_table(struct radeon_device *rdev)
        table->VddcVddciDelta = 4000;
        table->PhaseResponseTime = 0;
        table->MemoryThermThrottleEnable = 1;
-       table->PCIeBootLinkLevel = 0;
+       table->PCIeBootLinkLevel = pi->dpm_table.pcie_speed_table.count - 1;
        table->PCIeGenInterval = 1;
        if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2)
                table->SVI2Enable  = 1;
@@ -3320,6 +3752,8 @@ static int ci_upload_dpm_level_enable_mask(struct radeon_device *rdev)
        struct ci_power_info *pi = ci_get_pi(rdev);
        PPSMC_Result result;
 
+       ci_apply_disp_minimum_voltage_request(rdev);
+
        if (!pi->sclk_dpm_key_disabled) {
                if (pi->dpm_level_enable_mask.sclk_dpm_enable_mask) {
                        result = ci_send_msg_to_smc_with_parameter(rdev,
@@ -3339,7 +3773,7 @@ static int ci_upload_dpm_level_enable_mask(struct radeon_device *rdev)
                                return -EINVAL;
                }
        }
-
+#if 0
        if (!pi->pcie_dpm_key_disabled) {
                if (pi->dpm_level_enable_mask.pcie_dpm_enable_mask) {
                        result = ci_send_msg_to_smc_with_parameter(rdev,
@@ -3349,9 +3783,7 @@ static int ci_upload_dpm_level_enable_mask(struct radeon_device *rdev)
                                return -EINVAL;
                }
        }
-
-       ci_apply_disp_minimum_voltage_request(rdev);
-
+#endif
        return 0;
 }
 
@@ -3377,7 +3809,7 @@ static void ci_find_dpm_states_clocks_in_dpm_table(struct radeon_device *rdev,
                pi->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
        } else {
                /* XXX check display min clock requirements */
-               if (0 != CISLAND_MINIMUM_ENGINE_CLOCK)
+               if (CISLAND_MINIMUM_ENGINE_CLOCK != CISLAND_MINIMUM_ENGINE_CLOCK)
                        pi->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK;
        }
 
@@ -3707,62 +4139,61 @@ int ci_dpm_force_performance_level(struct radeon_device *rdev,
                                   enum radeon_dpm_forced_level level)
 {
        struct ci_power_info *pi = ci_get_pi(rdev);
-       PPSMC_Result smc_result;
        u32 tmp, levels, i;
        int ret;
 
        if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
-               if ((!pi->sclk_dpm_key_disabled) &&
-                   pi->dpm_level_enable_mask.sclk_dpm_enable_mask) {
+               if ((!pi->pcie_dpm_key_disabled) &&
+                   pi->dpm_level_enable_mask.pcie_dpm_enable_mask) {
                        levels = 0;
-                       tmp = pi->dpm_level_enable_mask.sclk_dpm_enable_mask;
+                       tmp = pi->dpm_level_enable_mask.pcie_dpm_enable_mask;
                        while (tmp >>= 1)
                                levels++;
                        if (levels) {
-                               ret = ci_dpm_force_state_sclk(rdev, levels);
+                               ret = ci_dpm_force_state_pcie(rdev, level);
                                if (ret)
                                        return ret;
                                for (i = 0; i < rdev->usec_timeout; i++) {
-                                       tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) &
-                                              CURR_SCLK_INDEX_MASK) >> CURR_SCLK_INDEX_SHIFT;
+                                       tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX_1) &
+                                              CURR_PCIE_INDEX_MASK) >> CURR_PCIE_INDEX_SHIFT;
                                        if (tmp == levels)
                                                break;
                                        udelay(1);
                                }
                        }
                }
-               if ((!pi->mclk_dpm_key_disabled) &&
-                   pi->dpm_level_enable_mask.mclk_dpm_enable_mask) {
+               if ((!pi->sclk_dpm_key_disabled) &&
+                   pi->dpm_level_enable_mask.sclk_dpm_enable_mask) {
                        levels = 0;
-                       tmp = pi->dpm_level_enable_mask.mclk_dpm_enable_mask;
+                       tmp = pi->dpm_level_enable_mask.sclk_dpm_enable_mask;
                        while (tmp >>= 1)
                                levels++;
                        if (levels) {
-                               ret = ci_dpm_force_state_mclk(rdev, levels);
+                               ret = ci_dpm_force_state_sclk(rdev, levels);
                                if (ret)
                                        return ret;
                                for (i = 0; i < rdev->usec_timeout; i++) {
                                        tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) &
-                                              CURR_MCLK_INDEX_MASK) >> CURR_MCLK_INDEX_SHIFT;
+                                              CURR_SCLK_INDEX_MASK) >> CURR_SCLK_INDEX_SHIFT;
                                        if (tmp == levels)
                                                break;
                                        udelay(1);
                                }
                        }
                }
-               if ((!pi->pcie_dpm_key_disabled) &&
-                   pi->dpm_level_enable_mask.pcie_dpm_enable_mask) {
+               if ((!pi->mclk_dpm_key_disabled) &&
+                   pi->dpm_level_enable_mask.mclk_dpm_enable_mask) {
                        levels = 0;
-                       tmp = pi->dpm_level_enable_mask.pcie_dpm_enable_mask;
+                       tmp = pi->dpm_level_enable_mask.mclk_dpm_enable_mask;
                        while (tmp >>= 1)
                                levels++;
                        if (levels) {
-                               ret = ci_dpm_force_state_pcie(rdev, level);
+                               ret = ci_dpm_force_state_mclk(rdev, levels);
                                if (ret)
                                        return ret;
                                for (i = 0; i < rdev->usec_timeout; i++) {
-                                       tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX_1) &
-                                              CURR_PCIE_INDEX_MASK) >> CURR_PCIE_INDEX_SHIFT;
+                                       tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) &
+                                              CURR_MCLK_INDEX_MASK) >> CURR_MCLK_INDEX_SHIFT;
                                        if (tmp == levels)
                                                break;
                                        udelay(1);
@@ -3816,21 +4247,17 @@ int ci_dpm_force_performance_level(struct radeon_device *rdev,
                        }
                }
        } else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) {
-               if (!pi->sclk_dpm_key_disabled) {
-                       smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel);
-                       if (smc_result != PPSMC_Result_OK)
-                               return -EINVAL;
-               }
-               if (!pi->mclk_dpm_key_disabled) {
-                       smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_MCLKDPM_NoForcedLevel);
-                       if (smc_result != PPSMC_Result_OK)
-                               return -EINVAL;
-               }
                if (!pi->pcie_dpm_key_disabled) {
-                       smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_PCIeDPM_UnForceLevel);
+                       PPSMC_Result smc_result;
+
+                       smc_result = ci_send_msg_to_smc(rdev,
+                                                       PPSMC_MSG_PCIeDPM_UnForceLevel);
                        if (smc_result != PPSMC_Result_OK)
                                return -EINVAL;
                }
+               ret = ci_upload_dpm_level_enable_mask(rdev);
+               if (ret)
+                       return ret;
        }
 
        rdev->pm.dpm.forced_level = level;
@@ -4036,6 +4463,96 @@ static int ci_copy_vbios_mc_reg_table(const struct atom_mc_reg_table *table,
        return 0;
 }
 
+static int ci_register_patching_mc_seq(struct radeon_device *rdev,
+                                      struct ci_mc_reg_table *table)
+{
+       u8 i, k;
+       u32 tmp;
+       bool patch;
+
+       tmp = RREG32(MC_SEQ_MISC0);
+       patch = ((tmp & 0x0000f00) == 0x300) ? true : false;
+
+       if (patch &&
+           ((rdev->pdev->device == 0x67B0) ||
+            (rdev->pdev->device == 0x67B1))) {
+               for (i = 0; i < table->last; i++) {
+                       if (table->last >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
+                               return -EINVAL;
+                       switch(table->mc_reg_address[i].s1 >> 2) {
+                       case MC_SEQ_MISC1:
+                               for (k = 0; k < table->num_entries; k++) {
+                                       if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
+                                           (table->mc_reg_table_entry[k].mclk_max == 137500))
+                                               table->mc_reg_table_entry[k].mc_data[i] =
+                                                       (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFF8) |
+                                                       0x00000007;
+                               }
+                               break;
+                       case MC_SEQ_WR_CTL_D0:
+                               for (k = 0; k < table->num_entries; k++) {
+                                       if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
+                                           (table->mc_reg_table_entry[k].mclk_max == 137500))
+                                               table->mc_reg_table_entry[k].mc_data[i] =
+                                                       (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFF0F00) |
+                                                       0x0000D0DD;
+                               }
+                               break;
+                       case MC_SEQ_WR_CTL_D1:
+                               for (k = 0; k < table->num_entries; k++) {
+                                       if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
+                                           (table->mc_reg_table_entry[k].mclk_max == 137500))
+                                               table->mc_reg_table_entry[k].mc_data[i] =
+                                                       (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFF0F00) |
+                                                       0x0000D0DD;
+                               }
+                               break;
+                       case MC_SEQ_WR_CTL_2:
+                               for (k = 0; k < table->num_entries; k++) {
+                                       if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
+                                           (table->mc_reg_table_entry[k].mclk_max == 137500))
+                                               table->mc_reg_table_entry[k].mc_data[i] = 0;
+                               }
+                               break;
+                       case MC_SEQ_CAS_TIMING:
+                               for (k = 0; k < table->num_entries; k++) {
+                                       if (table->mc_reg_table_entry[k].mclk_max == 125000)
+                                               table->mc_reg_table_entry[k].mc_data[i] =
+                                                       (table->mc_reg_table_entry[k].mc_data[i] & 0xFFE0FE0F) |
+                                                       0x000C0140;
+                                       else if (table->mc_reg_table_entry[k].mclk_max == 137500)
+                                               table->mc_reg_table_entry[k].mc_data[i] =
+                                                       (table->mc_reg_table_entry[k].mc_data[i] & 0xFFE0FE0F) |
+                                                       0x000C0150;
+                               }
+                               break;
+                       case MC_SEQ_MISC_TIMING:
+                               for (k = 0; k < table->num_entries; k++) {
+                                       if (table->mc_reg_table_entry[k].mclk_max == 125000)
+                                               table->mc_reg_table_entry[k].mc_data[i] =
+                                                       (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFE0) |
+                                                       0x00000030;
+                                       else if (table->mc_reg_table_entry[k].mclk_max == 137500)
+                                               table->mc_reg_table_entry[k].mc_data[i] =
+                                                       (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFE0) |
+                                                       0x00000035;
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
+               WREG32(MC_SEQ_IO_DEBUG_INDEX, 3);
+               tmp = RREG32(MC_SEQ_IO_DEBUG_DATA);
+               tmp = (tmp & 0xFFF8FFFF) | (1 << 16);
+               WREG32(MC_SEQ_IO_DEBUG_INDEX, 3);
+               WREG32(MC_SEQ_IO_DEBUG_DATA, tmp);
+       }
+
+       return 0;
+}
+
 static int ci_initialize_mc_reg_table(struct radeon_device *rdev)
 {
        struct ci_power_info *pi = ci_get_pi(rdev);
@@ -4079,6 +4596,10 @@ static int ci_initialize_mc_reg_table(struct radeon_device *rdev)
 
        ci_set_s0_mc_reg_index(ci_table);
 
+       ret = ci_register_patching_mc_seq(rdev, ci_table);
+       if (ret)
+               goto init_mc_done;
+
        ret = ci_set_mc_special_registers(rdev, ci_table);
        if (ret)
                goto init_mc_done;
@@ -4675,36 +5196,51 @@ int ci_dpm_enable(struct radeon_device *rdev)
                return ret;
        }
 
+       ret = ci_power_control_set_level(rdev);
+       if (ret) {
+               DRM_ERROR("ci_power_control_set_level failed\n");
+               return ret;
+       }
+
        ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
 
+       ret = ci_enable_thermal_based_sclk_dpm(rdev, true);
+       if (ret) {
+               DRM_ERROR("ci_enable_thermal_based_sclk_dpm failed\n");
+               return ret;
+       }
+
+       ci_thermal_start_thermal_controller(rdev);
+
        ci_update_current_ps(rdev, boot_ps);
 
        return 0;
 }
 
-int ci_dpm_late_enable(struct radeon_device *rdev)
+static int ci_set_temperature_range(struct radeon_device *rdev)
 {
        int ret;
 
-       if (rdev->irq.installed &&
-           r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
-#if 0
-               PPSMC_Result result;
-#endif
-               ret = ci_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
-               if (ret) {
-                       DRM_ERROR("ci_set_thermal_temperature_range failed\n");
-                       return ret;
-               }
-               rdev->irq.dpm_thermal = true;
-               radeon_irq_set(rdev);
-#if 0
-               result = ci_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
+       ret = ci_thermal_enable_alert(rdev, false);
+       if (ret)
+               return ret;
+       ret = ci_thermal_set_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+       if (ret)
+               return ret;
+       ret = ci_thermal_enable_alert(rdev, true);
+       if (ret)
+               return ret;
 
-               if (result != PPSMC_Result_OK)
-                       DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
-#endif
-       }
+       return ret;
+}
+
+int ci_dpm_late_enable(struct radeon_device *rdev)
+{
+       int ret;
+
+       ret = ci_set_temperature_range(rdev);
+       if (ret)
+               return ret;
 
        ci_dpm_powergate_uvd(rdev, true);
 
@@ -4721,6 +5257,8 @@ void ci_dpm_disable(struct radeon_device *rdev)
        if (!ci_is_smc_running(rdev))
                return;
 
+       ci_thermal_stop_thermal_controller(rdev);
+
        if (pi->thermal_protection)
                ci_enable_thermal_protection(rdev, false);
        ci_enable_power_containment(rdev, false);
@@ -4729,12 +5267,13 @@ void ci_dpm_disable(struct radeon_device *rdev)
        ci_enable_spread_spectrum(rdev, false);
        ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, false);
        ci_stop_dpm(rdev);
-       ci_enable_ds_master_switch(rdev, true);
+       ci_enable_ds_master_switch(rdev, false);
        ci_enable_ulv(rdev, false);
        ci_clear_vc(rdev);
        ci_reset_to_default(rdev);
        ci_dpm_stop_smc(rdev);
        ci_force_switch_to_arb_f0(rdev);
+       ci_enable_thermal_based_sclk_dpm(rdev, false);
 
        ci_update_current_ps(rdev, boot_ps);
 }
@@ -4804,11 +5343,6 @@ int ci_dpm_set_power_state(struct radeon_device *rdev)
        return 0;
 }
 
-int ci_dpm_power_control_set_level(struct radeon_device *rdev)
-{
-       return ci_power_control_set_level(rdev);
-}
-
 void ci_dpm_reset_asic(struct radeon_device *rdev)
 {
        ci_set_boot_state(rdev);
@@ -5068,6 +5602,8 @@ void ci_dpm_fini(struct radeon_device *rdev)
 int ci_dpm_init(struct radeon_device *rdev)
 {
        int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
+       SMU7_Discrete_DpmTable  *dpm_table;
+       struct radeon_gpio_rec gpio;
        u16 data_offset, size;
        u8 frev, crev;
        struct ci_power_info *pi;
@@ -5137,6 +5673,7 @@ int ci_dpm_init(struct radeon_device *rdev)
        pi->sclk_dpm_key_disabled = 0;
        pi->mclk_dpm_key_disabled = 0;
        pi->pcie_dpm_key_disabled = 0;
+       pi->thermal_sclk_dpm_enabled = 0;
 
        /* mclk dpm is unstable on some R7 260X cards with the old mc ucode */
        if ((rdev->pdev->device == 0x6658) &&
@@ -5201,6 +5738,55 @@ int ci_dpm_init(struct radeon_device *rdev)
 
        pi->uvd_enabled = false;
 
+       dpm_table = &pi->smc_state_table;
+
+       gpio = radeon_atombios_lookup_gpio(rdev, VDDC_VRHOT_GPIO_PINID);
+       if (gpio.valid) {
+               dpm_table->VRHotGpio = gpio.shift;
+               rdev->pm.dpm.platform_caps |= ATOM_PP_PLATFORM_CAP_REGULATOR_HOT;
+       } else {
+               dpm_table->VRHotGpio = CISLANDS_UNUSED_GPIO_PIN;
+               rdev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_REGULATOR_HOT;
+       }
+
+       gpio = radeon_atombios_lookup_gpio(rdev, PP_AC_DC_SWITCH_GPIO_PINID);
+       if (gpio.valid) {
+               dpm_table->AcDcGpio = gpio.shift;
+               rdev->pm.dpm.platform_caps |= ATOM_PP_PLATFORM_CAP_HARDWAREDC;
+       } else {
+               dpm_table->AcDcGpio = CISLANDS_UNUSED_GPIO_PIN;
+               rdev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_HARDWAREDC;
+       }
+
+       gpio = radeon_atombios_lookup_gpio(rdev, VDDC_PCC_GPIO_PINID);
+       if (gpio.valid) {
+               u32 tmp = RREG32_SMC(CNB_PWRMGT_CNTL);
+
+               switch (gpio.shift) {
+               case 0:
+                       tmp &= ~GNB_SLOW_MODE_MASK;
+                       tmp |= GNB_SLOW_MODE(1);
+                       break;
+               case 1:
+                       tmp &= ~GNB_SLOW_MODE_MASK;
+                       tmp |= GNB_SLOW_MODE(2);
+                       break;
+               case 2:
+                       tmp |= GNB_SLOW;
+                       break;
+               case 3:
+                       tmp |= FORCE_NB_PS1;
+                       break;
+               case 4:
+                       tmp |= DPM_ENABLED;
+                       break;
+               default:
+                       DRM_ERROR("Invalid PCC GPIO: %u!\n", gpio.shift);
+                       break;
+               }
+               WREG32_SMC(CNB_PWRMGT_CNTL, tmp);
+       }
+
        pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_NONE;
        pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_NONE;
        pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_NONE;
@@ -5262,6 +5848,9 @@ int ci_dpm_init(struct radeon_device *rdev)
                rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc =
                        rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
 
+       pi->fan_ctrl_is_in_default_mode = true;
+       rdev->pm.dpm.fan.ucode_fan_control = false;
+
        return 0;
 }
 
index 93bbed977ffb4631ef77eb57a5fa937f57b67cb6..84e3d3bcf9f327a6a0f410d951ce841090bf9bb0 100644 (file)
@@ -33,6 +33,8 @@
 
 #define CISLANDS_MAX_HARDWARE_POWERLEVELS 2
 
+#define CISLANDS_UNUSED_GPIO_PIN 0x7F
+
 struct ci_pl {
        u32 mclk;
        u32 sclk;
@@ -237,6 +239,7 @@ struct ci_power_info {
        u32 sclk_dpm_key_disabled;
        u32 mclk_dpm_key_disabled;
        u32 pcie_dpm_key_disabled;
+       u32 thermal_sclk_dpm_enabled;
        struct ci_pcie_perf_range pcie_gen_performance;
        struct ci_pcie_perf_range pcie_lane_performance;
        struct ci_pcie_perf_range pcie_gen_powersaving;
@@ -264,6 +267,7 @@ struct ci_power_info {
        bool caps_automatic_dc_transition;
        bool caps_sclk_throttle_low_notification;
        bool caps_dynamic_ac_timing;
+       bool caps_od_fuzzy_fan_control_support;
        /* flags */
        bool thermal_protection;
        bool pcie_performance_request;
@@ -285,6 +289,10 @@ struct ci_power_info {
        struct ci_ps current_ps;
        struct radeon_ps requested_rps;
        struct ci_ps requested_ps;
+       /* fan control */
+       bool fan_ctrl_is_in_default_mode;
+       u32 t_min;
+       u32 fan_ctrl_default_mode;
 };
 
 #define CISLANDS_VOLTAGE_CONTROL_NONE                   0x0
index b630edc2fd0c5d2b27c78bc8042eece5041076d5..e78bcad7a43e0dbef02ceb4854cef8d76837573b 100644 (file)
@@ -129,7 +129,7 @@ void ci_reset_smc(struct radeon_device *rdev)
 
 int ci_program_jump_on_start(struct radeon_device *rdev)
 {
-       static u8 data[] = { 0xE0, 0x00, 0x80, 0x40 };
+       static const u8 data[] = { 0xE0, 0x00, 0x80, 0x40 };
 
        return ci_copy_bytes_to_smc(rdev, 0x0, data, 4, sizeof(data)+1);
 }
index 89c01fa6dd8e3208fc428379e36264560133b818..6dcde3798b45a026f0be30f8e7bffb8b254ace81 100644 (file)
@@ -32,6 +32,7 @@
 #include "cik_blit_shaders.h"
 #include "radeon_ucode.h"
 #include "clearstate_ci.h"
+#include "radeon_kfd.h"
 
 MODULE_FIRMWARE("radeon/BONAIRE_pfp.bin");
 MODULE_FIRMWARE("radeon/BONAIRE_me.bin");
@@ -1563,6 +1564,8 @@ static const u32 godavari_golden_registers[] =
 
 static void cik_init_golden_registers(struct radeon_device *rdev)
 {
+       /* Some of the registers might be dependent on GRBM_GFX_INDEX */
+       mutex_lock(&rdev->grbm_idx_mutex);
        switch (rdev->family) {
        case CHIP_BONAIRE:
                radeon_program_register_sequence(rdev,
@@ -1637,6 +1640,7 @@ static void cik_init_golden_registers(struct radeon_device *rdev)
        default:
                break;
        }
+       mutex_unlock(&rdev->grbm_idx_mutex);
 }
 
 /**
@@ -1806,7 +1810,7 @@ int ci_mc_load_microcode(struct radeon_device *rdev)
 {
        const __be32 *fw_data = NULL;
        const __le32 *new_fw_data = NULL;
-       u32 running, blackout = 0;
+       u32 running, blackout = 0, tmp;
        u32 *io_mc_regs = NULL;
        const __le32 *new_io_mc_regs = NULL;
        int i, regs_size, ucode_size;
@@ -1866,6 +1870,15 @@ int ci_mc_load_microcode(struct radeon_device *rdev)
                                WREG32(MC_SEQ_IO_DEBUG_DATA, io_mc_regs[(i << 1) + 1]);
                        }
                }
+
+               tmp = RREG32(MC_SEQ_MISC0);
+               if ((rdev->pdev->device == 0x6649) && ((tmp & 0xff00) == 0x5600)) {
+                       WREG32(MC_SEQ_IO_DEBUG_INDEX, 5);
+                       WREG32(MC_SEQ_IO_DEBUG_DATA, 0x00000023);
+                       WREG32(MC_SEQ_IO_DEBUG_INDEX, 9);
+                       WREG32(MC_SEQ_IO_DEBUG_DATA, 0x000001f0);
+               }
+
                /* load the MC ucode */
                for (i = 0; i < ucode_size; i++) {
                        if (rdev->new_fw)
@@ -3419,6 +3432,7 @@ static void cik_setup_rb(struct radeon_device *rdev,
        u32 disabled_rbs = 0;
        u32 enabled_rbs = 0;
 
+       mutex_lock(&rdev->grbm_idx_mutex);
        for (i = 0; i < se_num; i++) {
                for (j = 0; j < sh_per_se; j++) {
                        cik_select_se_sh(rdev, i, j);
@@ -3430,6 +3444,7 @@ static void cik_setup_rb(struct radeon_device *rdev,
                }
        }
        cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
+       mutex_unlock(&rdev->grbm_idx_mutex);
 
        mask = 1;
        for (i = 0; i < max_rb_num_per_se * se_num; i++) {
@@ -3440,6 +3455,7 @@ static void cik_setup_rb(struct radeon_device *rdev,
 
        rdev->config.cik.backend_enable_mask = enabled_rbs;
 
+       mutex_lock(&rdev->grbm_idx_mutex);
        for (i = 0; i < se_num; i++) {
                cik_select_se_sh(rdev, i, 0xffffffff);
                data = 0;
@@ -3467,6 +3483,7 @@ static void cik_setup_rb(struct radeon_device *rdev,
                WREG32(PA_SC_RASTER_CONFIG, data);
        }
        cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
+       mutex_unlock(&rdev->grbm_idx_mutex);
 }
 
 /**
@@ -3684,6 +3701,12 @@ static void cik_gpu_init(struct radeon_device *rdev)
        /* set HW defaults for 3D engine */
        WREG32(CP_MEQ_THRESHOLDS, MEQ1_START(0x30) | MEQ2_START(0x60));
 
+       mutex_lock(&rdev->grbm_idx_mutex);
+       /*
+        * making sure that the following register writes will be broadcasted
+        * to all the shaders
+        */
+       cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
        WREG32(SX_DEBUG_1, 0x20);
 
        WREG32(TA_CNTL_AUX, 0x00010000);
@@ -3739,6 +3762,7 @@ static void cik_gpu_init(struct radeon_device *rdev)
 
        WREG32(PA_CL_ENHANCE, CLIP_VTX_REORDER_ENA | NUM_CLIP_SEQ(3));
        WREG32(PA_SC_ENHANCE, ENABLE_PA_SC_OUT_OF_ORDER);
+       mutex_unlock(&rdev->grbm_idx_mutex);
 
        udelay(50);
 }
@@ -3970,31 +3994,27 @@ struct radeon_fence *cik_copy_cpdma(struct radeon_device *rdev,
                                    unsigned num_gpu_pages,
                                    struct reservation_object *resv)
 {
-       struct radeon_semaphore *sem = NULL;
        struct radeon_fence *fence;
+       struct radeon_sync sync;
        int ring_index = rdev->asic->copy.blit_ring_index;
        struct radeon_ring *ring = &rdev->ring[ring_index];
        u32 size_in_bytes, cur_size_in_bytes, control;
        int i, num_loops;
        int r = 0;
 
-       r = radeon_semaphore_create(rdev, &sem);
-       if (r) {
-               DRM_ERROR("radeon: moving bo (%d).\n", r);
-               return ERR_PTR(r);
-       }
+       radeon_sync_create(&sync);
 
        size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
        num_loops = DIV_ROUND_UP(size_in_bytes, 0x1fffff);
        r = radeon_ring_lock(rdev, ring, num_loops * 7 + 18);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
-               radeon_semaphore_free(rdev, &sem, NULL);
+               radeon_sync_free(rdev, &sync, NULL);
                return ERR_PTR(r);
        }
 
-       radeon_semaphore_sync_resv(rdev, sem, resv, false);
-       radeon_semaphore_sync_rings(rdev, sem, ring->idx);
+       radeon_sync_resv(rdev, &sync, resv, false);
+       radeon_sync_rings(rdev, &sync, ring->idx);
 
        for (i = 0; i < num_loops; i++) {
                cur_size_in_bytes = size_in_bytes;
@@ -4018,12 +4038,12 @@ struct radeon_fence *cik_copy_cpdma(struct radeon_device *rdev,
        r = radeon_fence_emit(rdev, &fence, ring->idx);
        if (r) {
                radeon_ring_unlock_undo(rdev, ring);
-               radeon_semaphore_free(rdev, &sem, NULL);
+               radeon_sync_free(rdev, &sync, NULL);
                return ERR_PTR(r);
        }
 
        radeon_ring_unlock_commit(rdev, ring, false);
-       radeon_semaphore_free(rdev, &sem, fence);
+       radeon_sync_free(rdev, &sync, fence);
 
        return fence;
 }
@@ -4046,6 +4066,7 @@ struct radeon_fence *cik_copy_cpdma(struct radeon_device *rdev,
 void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
 {
        struct radeon_ring *ring = &rdev->ring[ib->ring];
+       unsigned vm_id = ib->vm ? ib->vm->ids[ib->ring].id : 0;
        u32 header, control = INDIRECT_BUFFER_VALID;
 
        if (ib->is_const_ib) {
@@ -4074,8 +4095,7 @@ void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
                header = PACKET3(PACKET3_INDIRECT_BUFFER, 2);
        }
 
-       control |= ib->length_dw |
-               (ib->vm ? (ib->vm->id << 24) : 0);
+       control |= ib->length_dw | (vm_id << 24);
 
        radeon_ring_write(ring, header);
        radeon_ring_write(ring,
@@ -4675,12 +4695,11 @@ static int cik_mec_init(struct radeon_device *rdev)
        /*
         * KV:    2 MEC, 4 Pipes/MEC, 8 Queues/Pipe - 64 Queues total
         * CI/KB: 1 MEC, 4 Pipes/MEC, 8 Queues/Pipe - 32 Queues total
+        * Nonetheless, we assign only 1 pipe because all other pipes will
+        * be handled by KFD
         */
-       if (rdev->family == CHIP_KAVERI)
-               rdev->mec.num_mec = 2;
-       else
-               rdev->mec.num_mec = 1;
-       rdev->mec.num_pipe = 4;
+       rdev->mec.num_mec = 1;
+       rdev->mec.num_pipe = 1;
        rdev->mec.num_queue = rdev->mec.num_mec * rdev->mec.num_pipe * 8;
 
        if (rdev->mec.hpd_eop_obj == NULL) {
@@ -4822,28 +4841,24 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
 
        /* init the pipes */
        mutex_lock(&rdev->srbm_mutex);
-       for (i = 0; i < (rdev->mec.num_pipe * rdev->mec.num_mec); i++) {
-               int me = (i < 4) ? 1 : 2;
-               int pipe = (i < 4) ? i : (i - 4);
 
-               eop_gpu_addr = rdev->mec.hpd_eop_gpu_addr + (i * MEC_HPD_SIZE * 2);
+       eop_gpu_addr = rdev->mec.hpd_eop_gpu_addr;
 
-               cik_srbm_select(rdev, me, pipe, 0, 0);
+       cik_srbm_select(rdev, 0, 0, 0, 0);
 
-               /* write the EOP addr */
-               WREG32(CP_HPD_EOP_BASE_ADDR, eop_gpu_addr >> 8);
-               WREG32(CP_HPD_EOP_BASE_ADDR_HI, upper_32_bits(eop_gpu_addr) >> 8);
+       /* write the EOP addr */
+       WREG32(CP_HPD_EOP_BASE_ADDR, eop_gpu_addr >> 8);
+       WREG32(CP_HPD_EOP_BASE_ADDR_HI, upper_32_bits(eop_gpu_addr) >> 8);
 
-               /* set the VMID assigned */
-               WREG32(CP_HPD_EOP_VMID, 0);
+       /* set the VMID assigned */
+       WREG32(CP_HPD_EOP_VMID, 0);
+
+       /* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */
+       tmp = RREG32(CP_HPD_EOP_CONTROL);
+       tmp &= ~EOP_SIZE_MASK;
+       tmp |= order_base_2(MEC_HPD_SIZE / 8);
+       WREG32(CP_HPD_EOP_CONTROL, tmp);
 
-               /* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */
-               tmp = RREG32(CP_HPD_EOP_CONTROL);
-               tmp &= ~EOP_SIZE_MASK;
-               tmp |= order_base_2(MEC_HPD_SIZE / 8);
-               WREG32(CP_HPD_EOP_CONTROL, tmp);
-       }
-       cik_srbm_select(rdev, 0, 0, 0, 0);
        mutex_unlock(&rdev->srbm_mutex);
 
        /* init the queues.  Just two for now. */
@@ -5897,8 +5912,13 @@ int cik_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
  */
 int cik_vm_init(struct radeon_device *rdev)
 {
-       /* number of VMs */
-       rdev->vm_manager.nvm = 16;
+       /*
+        * number of VMs
+        * VMID 0 is reserved for System
+        * radeon graphics/compute will use VMIDs 1-7
+        * amdkfd will use VMIDs 8-15
+        */
+       rdev->vm_manager.nvm = RADEON_NUM_OF_VMIDS;
        /* base offset of vram pages */
        if (rdev->flags & RADEON_IS_IGP) {
                u64 tmp = RREG32(MC_VM_FB_OFFSET);
@@ -5958,26 +5978,23 @@ static void cik_vm_decode_fault(struct radeon_device *rdev,
  * Update the page table base and flush the VM TLB
  * using the CP (CIK).
  */
-void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
+void cik_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
+                 unsigned vm_id, uint64_t pd_addr)
 {
-       struct radeon_ring *ring = &rdev->ring[ridx];
-       int usepfp = (ridx == RADEON_RING_TYPE_GFX_INDEX);
-
-       if (vm == NULL)
-               return;
+       int usepfp = (ring->idx == RADEON_RING_TYPE_GFX_INDEX);
 
        radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
        radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) |
                                 WRITE_DATA_DST_SEL(0)));
-       if (vm->id < 8) {
+       if (vm_id < 8) {
                radeon_ring_write(ring,
-                                 (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2);
+                                 (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2)) >> 2);
        } else {
                radeon_ring_write(ring,
-                                 (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2);
+                                 (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm_id - 8) << 2)) >> 2);
        }
        radeon_ring_write(ring, 0);
-       radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
+       radeon_ring_write(ring, pd_addr >> 12);
 
        /* update SH_MEM_* regs */
        radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
@@ -5985,7 +6002,7 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
                                 WRITE_DATA_DST_SEL(0)));
        radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
        radeon_ring_write(ring, 0);
-       radeon_ring_write(ring, VMID(vm->id));
+       radeon_ring_write(ring, VMID(vm_id));
 
        radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 6));
        radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) |
@@ -6006,7 +6023,7 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
        radeon_ring_write(ring, VMID(0));
 
        /* HDP flush */
-       cik_hdp_flush_cp_ring_emit(rdev, ridx);
+       cik_hdp_flush_cp_ring_emit(rdev, ring->idx);
 
        /* bits 0-15 are the VM contexts0-15 */
        radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
@@ -6014,7 +6031,7 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
                                 WRITE_DATA_DST_SEL(0)));
        radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
        radeon_ring_write(ring, 0);
-       radeon_ring_write(ring, 1 << vm->id);
+       radeon_ring_write(ring, 1 << vm_id);
 
        /* compute doesn't have PFP */
        if (usepfp) {
@@ -6059,6 +6076,7 @@ static void cik_wait_for_rlc_serdes(struct radeon_device *rdev)
        u32 i, j, k;
        u32 mask;
 
+       mutex_lock(&rdev->grbm_idx_mutex);
        for (i = 0; i < rdev->config.cik.max_shader_engines; i++) {
                for (j = 0; j < rdev->config.cik.max_sh_per_se; j++) {
                        cik_select_se_sh(rdev, i, j);
@@ -6070,6 +6088,7 @@ static void cik_wait_for_rlc_serdes(struct radeon_device *rdev)
                }
        }
        cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
+       mutex_unlock(&rdev->grbm_idx_mutex);
 
        mask = SE_MASTER_BUSY_MASK | GC_MASTER_BUSY | TC0_MASTER_BUSY | TC1_MASTER_BUSY;
        for (k = 0; k < rdev->usec_timeout; k++) {
@@ -6204,10 +6223,12 @@ static int cik_rlc_resume(struct radeon_device *rdev)
        WREG32(RLC_LB_CNTR_INIT, 0);
        WREG32(RLC_LB_CNTR_MAX, 0x00008000);
 
+       mutex_lock(&rdev->grbm_idx_mutex);
        cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
        WREG32(RLC_LB_INIT_CU_MASK, 0xffffffff);
        WREG32(RLC_LB_PARAMS, 0x00600408);
        WREG32(RLC_LB_CNTL, 0x80000004);
+       mutex_unlock(&rdev->grbm_idx_mutex);
 
        WREG32(RLC_MC_CNTL, 0);
        WREG32(RLC_UCODE_CNTL, 0);
@@ -6274,11 +6295,13 @@ static void cik_enable_cgcg(struct radeon_device *rdev, bool enable)
 
                tmp = cik_halt_rlc(rdev);
 
+               mutex_lock(&rdev->grbm_idx_mutex);
                cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
                WREG32(RLC_SERDES_WR_CU_MASTER_MASK, 0xffffffff);
                WREG32(RLC_SERDES_WR_NONCU_MASTER_MASK, 0xffffffff);
                tmp2 = BPM_ADDR_MASK | CGCG_OVERRIDE_0 | CGLS_ENABLE;
                WREG32(RLC_SERDES_WR_CTRL, tmp2);
+               mutex_unlock(&rdev->grbm_idx_mutex);
 
                cik_update_rlc(rdev, tmp);
 
@@ -6314,17 +6337,20 @@ static void cik_enable_mgcg(struct radeon_device *rdev, bool enable)
                }
 
                orig = data = RREG32(RLC_CGTT_MGCG_OVERRIDE);
+               data |= 0x00000001;
                data &= 0xfffffffd;
                if (orig != data)
                        WREG32(RLC_CGTT_MGCG_OVERRIDE, data);
 
                tmp = cik_halt_rlc(rdev);
 
+               mutex_lock(&rdev->grbm_idx_mutex);
                cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
                WREG32(RLC_SERDES_WR_CU_MASTER_MASK, 0xffffffff);
                WREG32(RLC_SERDES_WR_NONCU_MASTER_MASK, 0xffffffff);
                data = BPM_ADDR_MASK | MGCG_OVERRIDE_0;
                WREG32(RLC_SERDES_WR_CTRL, data);
+               mutex_unlock(&rdev->grbm_idx_mutex);
 
                cik_update_rlc(rdev, tmp);
 
@@ -6345,7 +6371,7 @@ static void cik_enable_mgcg(struct radeon_device *rdev, bool enable)
                }
        } else {
                orig = data = RREG32(RLC_CGTT_MGCG_OVERRIDE);
-               data |= 0x00000002;
+               data |= 0x00000003;
                if (orig != data)
                        WREG32(RLC_CGTT_MGCG_OVERRIDE, data);
 
@@ -6368,11 +6394,13 @@ static void cik_enable_mgcg(struct radeon_device *rdev, bool enable)
 
                tmp = cik_halt_rlc(rdev);
 
+               mutex_lock(&rdev->grbm_idx_mutex);
                cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
                WREG32(RLC_SERDES_WR_CU_MASTER_MASK, 0xffffffff);
                WREG32(RLC_SERDES_WR_NONCU_MASTER_MASK, 0xffffffff);
                data = BPM_ADDR_MASK | MGCG_OVERRIDE_1;
                WREG32(RLC_SERDES_WR_CTRL, data);
+               mutex_unlock(&rdev->grbm_idx_mutex);
 
                cik_update_rlc(rdev, tmp);
        }
@@ -6801,10 +6829,12 @@ static u32 cik_get_cu_active_bitmap(struct radeon_device *rdev, u32 se, u32 sh)
        u32 mask = 0, tmp, tmp1;
        int i;
 
+       mutex_lock(&rdev->grbm_idx_mutex);
        cik_select_se_sh(rdev, se, sh);
        tmp = RREG32(CC_GC_SHADER_ARRAY_CONFIG);
        tmp1 = RREG32(GC_USER_SHADER_ARRAY_CONFIG);
        cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
+       mutex_unlock(&rdev->grbm_idx_mutex);
 
        tmp &= 0xffff0000;
 
@@ -7288,8 +7318,7 @@ static int cik_irq_init(struct radeon_device *rdev)
 int cik_irq_set(struct radeon_device *rdev)
 {
        u32 cp_int_cntl;
-       u32 cp_m1p0, cp_m1p1, cp_m1p2, cp_m1p3;
-       u32 cp_m2p0, cp_m2p1, cp_m2p2, cp_m2p3;
+       u32 cp_m1p0;
        u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;
        u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
        u32 grbm_int_cntl = 0;
@@ -7323,13 +7352,6 @@ int cik_irq_set(struct radeon_device *rdev)
        dma_cntl1 = RREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
 
        cp_m1p0 = RREG32(CP_ME1_PIPE0_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
-       cp_m1p1 = RREG32(CP_ME1_PIPE1_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
-       cp_m1p2 = RREG32(CP_ME1_PIPE2_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
-       cp_m1p3 = RREG32(CP_ME1_PIPE3_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
-       cp_m2p0 = RREG32(CP_ME2_PIPE0_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
-       cp_m2p1 = RREG32(CP_ME2_PIPE1_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
-       cp_m2p2 = RREG32(CP_ME2_PIPE2_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
-       cp_m2p3 = RREG32(CP_ME2_PIPE3_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
 
        if (rdev->flags & RADEON_IS_IGP)
                thermal_int = RREG32_SMC(CG_THERMAL_INT_CTRL) &
@@ -7351,33 +7373,6 @@ int cik_irq_set(struct radeon_device *rdev)
                        case 0:
                                cp_m1p0 |= TIME_STAMP_INT_ENABLE;
                                break;
-                       case 1:
-                               cp_m1p1 |= TIME_STAMP_INT_ENABLE;
-                               break;
-                       case 2:
-                               cp_m1p2 |= TIME_STAMP_INT_ENABLE;
-                               break;
-                       case 3:
-                               cp_m1p2 |= TIME_STAMP_INT_ENABLE;
-                               break;
-                       default:
-                               DRM_DEBUG("si_irq_set: sw int cp1 invalid pipe %d\n", ring->pipe);
-                               break;
-                       }
-               } else if (ring->me == 2) {
-                       switch (ring->pipe) {
-                       case 0:
-                               cp_m2p0 |= TIME_STAMP_INT_ENABLE;
-                               break;
-                       case 1:
-                               cp_m2p1 |= TIME_STAMP_INT_ENABLE;
-                               break;
-                       case 2:
-                               cp_m2p2 |= TIME_STAMP_INT_ENABLE;
-                               break;
-                       case 3:
-                               cp_m2p2 |= TIME_STAMP_INT_ENABLE;
-                               break;
                        default:
                                DRM_DEBUG("si_irq_set: sw int cp1 invalid pipe %d\n", ring->pipe);
                                break;
@@ -7394,33 +7389,6 @@ int cik_irq_set(struct radeon_device *rdev)
                        case 0:
                                cp_m1p0 |= TIME_STAMP_INT_ENABLE;
                                break;
-                       case 1:
-                               cp_m1p1 |= TIME_STAMP_INT_ENABLE;
-                               break;
-                       case 2:
-                               cp_m1p2 |= TIME_STAMP_INT_ENABLE;
-                               break;
-                       case 3:
-                               cp_m1p2 |= TIME_STAMP_INT_ENABLE;
-                               break;
-                       default:
-                               DRM_DEBUG("si_irq_set: sw int cp2 invalid pipe %d\n", ring->pipe);
-                               break;
-                       }
-               } else if (ring->me == 2) {
-                       switch (ring->pipe) {
-                       case 0:
-                               cp_m2p0 |= TIME_STAMP_INT_ENABLE;
-                               break;
-                       case 1:
-                               cp_m2p1 |= TIME_STAMP_INT_ENABLE;
-                               break;
-                       case 2:
-                               cp_m2p2 |= TIME_STAMP_INT_ENABLE;
-                               break;
-                       case 3:
-                               cp_m2p2 |= TIME_STAMP_INT_ENABLE;
-                               break;
                        default:
                                DRM_DEBUG("si_irq_set: sw int cp2 invalid pipe %d\n", ring->pipe);
                                break;
@@ -7509,13 +7477,6 @@ int cik_irq_set(struct radeon_device *rdev)
        WREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET, dma_cntl1);
 
        WREG32(CP_ME1_PIPE0_INT_CNTL, cp_m1p0);
-       WREG32(CP_ME1_PIPE1_INT_CNTL, cp_m1p1);
-       WREG32(CP_ME1_PIPE2_INT_CNTL, cp_m1p2);
-       WREG32(CP_ME1_PIPE3_INT_CNTL, cp_m1p3);
-       WREG32(CP_ME2_PIPE0_INT_CNTL, cp_m2p0);
-       WREG32(CP_ME2_PIPE1_INT_CNTL, cp_m2p1);
-       WREG32(CP_ME2_PIPE2_INT_CNTL, cp_m2p2);
-       WREG32(CP_ME2_PIPE3_INT_CNTL, cp_m2p3);
 
        WREG32(GRBM_INT_CNTL, grbm_int_cntl);
 
@@ -7832,6 +7793,10 @@ restart_ih:
        while (rptr != wptr) {
                /* wptr/rptr are in bytes! */
                ring_index = rptr / 4;
+
+               radeon_kfd_interrupt(rdev,
+                               (const void *) &rdev->ih.ring[ring_index]);
+
                src_id =  le32_to_cpu(rdev->ih.ring[ring_index]) & 0xff;
                src_data = le32_to_cpu(rdev->ih.ring[ring_index + 1]) & 0xfffffff;
                ring_id = le32_to_cpu(rdev->ih.ring[ring_index + 2]) & 0xff;
@@ -8521,6 +8486,10 @@ static int cik_startup(struct radeon_device *rdev)
        if (r)
                return r;
 
+       r = radeon_kfd_resume(rdev);
+       if (r)
+               return r;
+
        return 0;
 }
 
@@ -8569,6 +8538,7 @@ int cik_resume(struct radeon_device *rdev)
  */
 int cik_suspend(struct radeon_device *rdev)
 {
+       radeon_kfd_suspend(rdev);
        radeon_pm_suspend(rdev);
        dce6_audio_fini(rdev);
        radeon_vm_manager_fini(rdev);
index ca1bb6133580aaa30579945e32810dba8317ca8e..79c45e8a536b03405d061dec6e41eb0f3eea6ca7 100644 (file)
 
 #define CIK_LB_DESKTOP_HEIGHT                     0x6b0c
 
+#define CP_HQD_IQ_RPTR                                 0xC970u
+#define AQL_ENABLE                                     (1U << 0)
+
+#define IDLE                                   (1 << 2)
+
+struct cik_mqd {
+       uint32_t header;
+       uint32_t compute_dispatch_initiator;
+       uint32_t compute_dim_x;
+       uint32_t compute_dim_y;
+       uint32_t compute_dim_z;
+       uint32_t compute_start_x;
+       uint32_t compute_start_y;
+       uint32_t compute_start_z;
+       uint32_t compute_num_thread_x;
+       uint32_t compute_num_thread_y;
+       uint32_t compute_num_thread_z;
+       uint32_t compute_pipelinestat_enable;
+       uint32_t compute_perfcount_enable;
+       uint32_t compute_pgm_lo;
+       uint32_t compute_pgm_hi;
+       uint32_t compute_tba_lo;
+       uint32_t compute_tba_hi;
+       uint32_t compute_tma_lo;
+       uint32_t compute_tma_hi;
+       uint32_t compute_pgm_rsrc1;
+       uint32_t compute_pgm_rsrc2;
+       uint32_t compute_vmid;
+       uint32_t compute_resource_limits;
+       uint32_t compute_static_thread_mgmt_se0;
+       uint32_t compute_static_thread_mgmt_se1;
+       uint32_t compute_tmpring_size;
+       uint32_t compute_static_thread_mgmt_se2;
+       uint32_t compute_static_thread_mgmt_se3;
+       uint32_t compute_restart_x;
+       uint32_t compute_restart_y;
+       uint32_t compute_restart_z;
+       uint32_t compute_thread_trace_enable;
+       uint32_t compute_misc_reserved;
+       uint32_t compute_user_data_0;
+       uint32_t compute_user_data_1;
+       uint32_t compute_user_data_2;
+       uint32_t compute_user_data_3;
+       uint32_t compute_user_data_4;
+       uint32_t compute_user_data_5;
+       uint32_t compute_user_data_6;
+       uint32_t compute_user_data_7;
+       uint32_t compute_user_data_8;
+       uint32_t compute_user_data_9;
+       uint32_t compute_user_data_10;
+       uint32_t compute_user_data_11;
+       uint32_t compute_user_data_12;
+       uint32_t compute_user_data_13;
+       uint32_t compute_user_data_14;
+       uint32_t compute_user_data_15;
+       uint32_t cp_compute_csinvoc_count_lo;
+       uint32_t cp_compute_csinvoc_count_hi;
+       uint32_t cp_mqd_base_addr_lo;
+       uint32_t cp_mqd_base_addr_hi;
+       uint32_t cp_hqd_active;
+       uint32_t cp_hqd_vmid;
+       uint32_t cp_hqd_persistent_state;
+       uint32_t cp_hqd_pipe_priority;
+       uint32_t cp_hqd_queue_priority;
+       uint32_t cp_hqd_quantum;
+       uint32_t cp_hqd_pq_base_lo;
+       uint32_t cp_hqd_pq_base_hi;
+       uint32_t cp_hqd_pq_rptr;
+       uint32_t cp_hqd_pq_rptr_report_addr_lo;
+       uint32_t cp_hqd_pq_rptr_report_addr_hi;
+       uint32_t cp_hqd_pq_wptr_poll_addr_lo;
+       uint32_t cp_hqd_pq_wptr_poll_addr_hi;
+       uint32_t cp_hqd_pq_doorbell_control;
+       uint32_t cp_hqd_pq_wptr;
+       uint32_t cp_hqd_pq_control;
+       uint32_t cp_hqd_ib_base_addr_lo;
+       uint32_t cp_hqd_ib_base_addr_hi;
+       uint32_t cp_hqd_ib_rptr;
+       uint32_t cp_hqd_ib_control;
+       uint32_t cp_hqd_iq_timer;
+       uint32_t cp_hqd_iq_rptr;
+       uint32_t cp_hqd_dequeue_request;
+       uint32_t cp_hqd_dma_offload;
+       uint32_t cp_hqd_sema_cmd;
+       uint32_t cp_hqd_msg_type;
+       uint32_t cp_hqd_atomic0_preop_lo;
+       uint32_t cp_hqd_atomic0_preop_hi;
+       uint32_t cp_hqd_atomic1_preop_lo;
+       uint32_t cp_hqd_atomic1_preop_hi;
+       uint32_t cp_hqd_hq_status0;
+       uint32_t cp_hqd_hq_control0;
+       uint32_t cp_mqd_control;
+       uint32_t cp_mqd_query_time_lo;
+       uint32_t cp_mqd_query_time_hi;
+       uint32_t cp_mqd_connect_start_time_lo;
+       uint32_t cp_mqd_connect_start_time_hi;
+       uint32_t cp_mqd_connect_end_time_lo;
+       uint32_t cp_mqd_connect_end_time_hi;
+       uint32_t cp_mqd_connect_end_wf_count;
+       uint32_t cp_mqd_connect_end_pq_rptr;
+       uint32_t cp_mqd_connect_end_pq_wptr;
+       uint32_t cp_mqd_connect_end_ib_rptr;
+       uint32_t reserved_96;
+       uint32_t reserved_97;
+       uint32_t reserved_98;
+       uint32_t reserved_99;
+       uint32_t iqtimer_pkt_header;
+       uint32_t iqtimer_pkt_dw0;
+       uint32_t iqtimer_pkt_dw1;
+       uint32_t iqtimer_pkt_dw2;
+       uint32_t iqtimer_pkt_dw3;
+       uint32_t iqtimer_pkt_dw4;
+       uint32_t iqtimer_pkt_dw5;
+       uint32_t iqtimer_pkt_dw6;
+       uint32_t reserved_108;
+       uint32_t reserved_109;
+       uint32_t reserved_110;
+       uint32_t reserved_111;
+       uint32_t queue_doorbell_id0;
+       uint32_t queue_doorbell_id1;
+       uint32_t queue_doorbell_id2;
+       uint32_t queue_doorbell_id3;
+       uint32_t queue_doorbell_id4;
+       uint32_t queue_doorbell_id5;
+       uint32_t queue_doorbell_id6;
+       uint32_t queue_doorbell_id7;
+       uint32_t queue_doorbell_id8;
+       uint32_t queue_doorbell_id9;
+       uint32_t queue_doorbell_id10;
+       uint32_t queue_doorbell_id11;
+       uint32_t queue_doorbell_id12;
+       uint32_t queue_doorbell_id13;
+       uint32_t queue_doorbell_id14;
+       uint32_t queue_doorbell_id15;
+};
+
 #endif
index d748963af08b7ea3215cf6dcfbf9ff92bbec8b69..dde5c7e29eb200b6dc78f1fad46197e43e0013ed 100644 (file)
@@ -134,7 +134,7 @@ void cik_sdma_ring_ib_execute(struct radeon_device *rdev,
                              struct radeon_ib *ib)
 {
        struct radeon_ring *ring = &rdev->ring[ib->ring];
-       u32 extra_bits = (ib->vm ? ib->vm->id : 0) & 0xf;
+       u32 extra_bits = (ib->vm ? ib->vm->ids[ib->ring].id : 0) & 0xf;
 
        if (rdev->wb.enabled) {
                u32 next_rptr = ring->wptr + 5;
@@ -541,31 +541,27 @@ struct radeon_fence *cik_copy_dma(struct radeon_device *rdev,
                                  unsigned num_gpu_pages,
                                  struct reservation_object *resv)
 {
-       struct radeon_semaphore *sem = NULL;
        struct radeon_fence *fence;
+       struct radeon_sync sync;
        int ring_index = rdev->asic->copy.dma_ring_index;
        struct radeon_ring *ring = &rdev->ring[ring_index];
        u32 size_in_bytes, cur_size_in_bytes;
        int i, num_loops;
        int r = 0;
 
-       r = radeon_semaphore_create(rdev, &sem);
-       if (r) {
-               DRM_ERROR("radeon: moving bo (%d).\n", r);
-               return ERR_PTR(r);
-       }
+       radeon_sync_create(&sync);
 
        size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
        num_loops = DIV_ROUND_UP(size_in_bytes, 0x1fffff);
        r = radeon_ring_lock(rdev, ring, num_loops * 7 + 14);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
-               radeon_semaphore_free(rdev, &sem, NULL);
+               radeon_sync_free(rdev, &sync, NULL);
                return ERR_PTR(r);
        }
 
-       radeon_semaphore_sync_resv(rdev, sem, resv, false);
-       radeon_semaphore_sync_rings(rdev, sem, ring->idx);
+       radeon_sync_resv(rdev, &sync, resv, false);
+       radeon_sync_rings(rdev, &sync, ring->idx);
 
        for (i = 0; i < num_loops; i++) {
                cur_size_in_bytes = size_in_bytes;
@@ -586,12 +582,12 @@ struct radeon_fence *cik_copy_dma(struct radeon_device *rdev,
        r = radeon_fence_emit(rdev, &fence, ring->idx);
        if (r) {
                radeon_ring_unlock_undo(rdev, ring);
-               radeon_semaphore_free(rdev, &sem, NULL);
+               radeon_sync_free(rdev, &sync, NULL);
                return ERR_PTR(r);
        }
 
        radeon_ring_unlock_commit(rdev, ring, false);
-       radeon_semaphore_free(rdev, &sem, fence);
+       radeon_sync_free(rdev, &sync, fence);
 
        return fence;
 }
@@ -904,25 +900,21 @@ void cik_sdma_vm_pad_ib(struct radeon_ib *ib)
  * Update the page table base and flush the VM TLB
  * using sDMA (CIK).
  */
-void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
+void cik_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
+                     unsigned vm_id, uint64_t pd_addr)
 {
-       struct radeon_ring *ring = &rdev->ring[ridx];
-
-       if (vm == NULL)
-               return;
-
        radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
-       if (vm->id < 8) {
-               radeon_ring_write(ring, (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2);
+       if (vm_id < 8) {
+               radeon_ring_write(ring, (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2)) >> 2);
        } else {
-               radeon_ring_write(ring, (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2);
+               radeon_ring_write(ring, (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm_id - 8) << 2)) >> 2);
        }
-       radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
+       radeon_ring_write(ring, pd_addr >> 12);
 
        /* update SH_MEM_* regs */
        radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
        radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
-       radeon_ring_write(ring, VMID(vm->id));
+       radeon_ring_write(ring, VMID(vm_id));
 
        radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
        radeon_ring_write(ring, SH_MEM_BASES >> 2);
@@ -945,11 +937,11 @@ void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm
        radeon_ring_write(ring, VMID(0));
 
        /* flush HDP */
-       cik_sdma_hdp_flush_ring_emit(rdev, ridx);
+       cik_sdma_hdp_flush_ring_emit(rdev, ring->idx);
 
        /* flush TLB */
        radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
        radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
-       radeon_ring_write(ring, 1 << vm->id);
+       radeon_ring_write(ring, 1 << vm_id);
 }
 
index 0c6e1b55d9684aa620e6c665c915e3293a92c7ab..e4e88ca8b82eb29c5a4f637c12d8b701a88b4d1c 100644 (file)
@@ -30,6 +30,8 @@
 #define CIK_RB_BITMAP_WIDTH_PER_SH     2
 #define HAWAII_RB_BITMAP_WIDTH_PER_SH  4
 
+#define RADEON_NUM_OF_VMIDS    8
+
 /* DIDT IND registers */
 #define DIDT_SQ_CTRL0                                     0x0
 #       define DIDT_CTRL_EN                               (1 << 0)
 #define                DIG_THERM_DPM(x)                        ((x) << 14)
 #define                DIG_THERM_DPM_MASK                      0x003FC000
 #define                DIG_THERM_DPM_SHIFT                     14
-
+#define        CG_THERMAL_STATUS                               0xC0300008
+#define                FDO_PWM_DUTY(x)                         ((x) << 9)
+#define                FDO_PWM_DUTY_MASK                       (0xff << 9)
+#define                FDO_PWM_DUTY_SHIFT                      9
 #define        CG_THERMAL_INT                                  0xC030000C
 #define                CI_DIG_THERM_INTH(x)                    ((x) << 8)
 #define                CI_DIG_THERM_INTH_MASK                  0x0000FF00
 #define                CI_DIG_THERM_INTL_SHIFT                 16
 #define        THERM_INT_MASK_HIGH                     (1 << 24)
 #define        THERM_INT_MASK_LOW                      (1 << 25)
-
+#define        CG_MULT_THERMAL_CTRL                            0xC0300010
+#define                TEMP_SEL(x)                             ((x) << 20)
+#define                TEMP_SEL_MASK                           (0xff << 20)
+#define                TEMP_SEL_SHIFT                          20
 #define        CG_MULT_THERMAL_STATUS                          0xC0300014
 #define                ASIC_MAX_TEMP(x)                        ((x) << 0)
 #define                ASIC_MAX_TEMP_MASK                      0x000001ff
 #define                CTF_TEMP_MASK                           0x0003fe00
 #define                CTF_TEMP_SHIFT                          9
 
+#define        CG_FDO_CTRL0                                    0xC0300064
+#define                FDO_STATIC_DUTY(x)                      ((x) << 0)
+#define                FDO_STATIC_DUTY_MASK                    0x0000000F
+#define                FDO_STATIC_DUTY_SHIFT                   0
+#define        CG_FDO_CTRL1                                    0xC0300068
+#define                FMAX_DUTY100(x)                         ((x) << 0)
+#define                FMAX_DUTY100_MASK                       0x0000000F
+#define                FMAX_DUTY100_SHIFT                      0
+#define        CG_FDO_CTRL2                                    0xC030006C
+#define                TMIN(x)                                 ((x) << 0)
+#define                TMIN_MASK                               0x0000000F
+#define                TMIN_SHIFT                              0
+#define                FDO_PWM_MODE(x)                         ((x) << 11)
+#define                FDO_PWM_MODE_MASK                       (3 << 11)
+#define                FDO_PWM_MODE_SHIFT                      11
+#define                TACH_PWM_RESP_RATE(x)                   ((x) << 25)
+#define                TACH_PWM_RESP_RATE_MASK                 (0x7f << 25)
+#define                TACH_PWM_RESP_RATE_SHIFT                25
+#define CG_TACH_CTRL                                    0xC0300070
+#       define EDGE_PER_REV(x)                          ((x) << 0)
+#       define EDGE_PER_REV_MASK                        (0x7 << 0)
+#       define EDGE_PER_REV_SHIFT                       0
+#       define TARGET_PERIOD(x)                         ((x) << 3)
+#       define TARGET_PERIOD_MASK                       0xfffffff8
+#       define TARGET_PERIOD_SHIFT                      3
+#define CG_TACH_STATUS                                  0xC0300074
+#       define TACH_PERIOD(x)                           ((x) << 0)
+#       define TACH_PERIOD_MASK                         0xffffffff
+#       define TACH_PERIOD_SHIFT                        0
+
 #define CG_ECLK_CNTL                                    0xC05000AC
 #       define ECLK_DIVIDER_MASK                        0x7f
 #       define ECLK_DIR_CNTL_EN                         (1 << 8)
 #define                        SH_MEM_ALIGNMENT_MODE_UNALIGNED                 3
 #define                DEFAULT_MTYPE(x)                                ((x) << 4)
 #define                APE1_MTYPE(x)                                   ((x) << 7)
+/* valid for both DEFAULT_MTYPE and APE1_MTYPE */
+#define        MTYPE_CACHED                                    0
+#define        MTYPE_NONCACHED                                 3
 
 #define        SX_DEBUG_1                                      0x9060
 
 #define CP_HQD_ACTIVE                                     0xC91C
 #define CP_HQD_VMID                                       0xC920
 
+#define CP_HQD_PERSISTENT_STATE                                0xC924u
+#define        DEFAULT_CP_HQD_PERSISTENT_STATE                 (0x33U << 8)
+
+#define CP_HQD_PIPE_PRIORITY                           0xC928u
+#define CP_HQD_QUEUE_PRIORITY                          0xC92Cu
+#define CP_HQD_QUANTUM                                 0xC930u
+#define        QUANTUM_EN                                      1U
+#define        QUANTUM_SCALE_1MS                               (1U << 4)
+#define        QUANTUM_DURATION(x)                             ((x) << 8)
+
 #define CP_HQD_PQ_BASE                                    0xC934
 #define CP_HQD_PQ_BASE_HI                                 0xC938
 #define CP_HQD_PQ_RPTR                                    0xC93C
 #define                PRIV_STATE                              (1 << 30)
 #define                KMD_QUEUE                               (1 << 31)
 
-#define CP_HQD_DEQUEUE_REQUEST                          0xC974
+#define CP_HQD_IB_BASE_ADDR                            0xC95Cu
+#define CP_HQD_IB_BASE_ADDR_HI                 0xC960u
+#define CP_HQD_IB_RPTR                                 0xC964u
+#define CP_HQD_IB_CONTROL                              0xC968u
+#define        IB_ATC_EN                                       (1U << 23)
+#define        DEFAULT_MIN_IB_AVAIL_SIZE                       (3U << 20)
+
+#define CP_HQD_DEQUEUE_REQUEST                 0xC974
+#define        DEQUEUE_REQUEST_DRAIN                           1
+#define DEQUEUE_REQUEST_RESET                          2
 
 #define CP_MQD_CONTROL                                  0xC99C
 #define                MQD_VMID(x)                             ((x) << 0)
 #define                MQD_VMID_MASK                           (0xf << 0)
 
+#define CP_HQD_SEMA_CMD                                        0xC97Cu
+#define CP_HQD_MSG_TYPE                                        0xC980u
+#define CP_HQD_ATOMIC0_PREOP_LO                        0xC984u
+#define CP_HQD_ATOMIC0_PREOP_HI                        0xC988u
+#define CP_HQD_ATOMIC1_PREOP_LO                        0xC98Cu
+#define CP_HQD_ATOMIC1_PREOP_HI                        0xC990u
+#define CP_HQD_HQ_SCHEDULER0                   0xC994u
+#define CP_HQD_HQ_SCHEDULER1                   0xC998u
+
+#define SH_STATIC_MEM_CONFIG                   0x9604u
+
 #define DB_RENDER_CONTROL                               0x28000
 
 #define PA_SC_RASTER_CONFIG                             0x28350
 #define VCE_CMD_IB_AUTO                0x00000005
 #define VCE_CMD_SEMAPHORE      0x00000006
 
+#define ATC_VMID0_PASID_MAPPING                                        0x339Cu
+#define        ATC_VMID_PASID_MAPPING_UPDATE_STATUS    0x3398u
+#define        ATC_VMID_PASID_MAPPING_VALID                            (1U << 31)
+
+#define ATC_VM_APERTURE0_CNTL                                  0x3310u
+#define        ATS_ACCESS_MODE_NEVER                                           0
+#define        ATS_ACCESS_MODE_ALWAYS                                          1
+
+#define ATC_VM_APERTURE0_CNTL2                                 0x3318u
+#define ATC_VM_APERTURE0_HIGH_ADDR                             0x3308u
+#define ATC_VM_APERTURE0_LOW_ADDR                              0x3300u
+#define ATC_VM_APERTURE1_CNTL                                  0x3314u
+#define ATC_VM_APERTURE1_CNTL2                                 0x331Cu
+#define ATC_VM_APERTURE1_HIGH_ADDR                             0x330Cu
+#define ATC_VM_APERTURE1_LOW_ADDR                              0x3304u
+
 #endif
index 66bcfadeedd1a56265ea2f8121df864ecad4574e..96535aa8659c3ffe3df3ee2b208d6136aa4c4c35 100644 (file)
@@ -110,31 +110,27 @@ struct radeon_fence *evergreen_copy_dma(struct radeon_device *rdev,
                                        unsigned num_gpu_pages,
                                        struct reservation_object *resv)
 {
-       struct radeon_semaphore *sem = NULL;
        struct radeon_fence *fence;
+       struct radeon_sync sync;
        int ring_index = rdev->asic->copy.dma_ring_index;
        struct radeon_ring *ring = &rdev->ring[ring_index];
        u32 size_in_dw, cur_size_in_dw;
        int i, num_loops;
        int r = 0;
 
-       r = radeon_semaphore_create(rdev, &sem);
-       if (r) {
-               DRM_ERROR("radeon: moving bo (%d).\n", r);
-               return ERR_PTR(r);
-       }
+       radeon_sync_create(&sync);
 
        size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4;
        num_loops = DIV_ROUND_UP(size_in_dw, 0xfffff);
        r = radeon_ring_lock(rdev, ring, num_loops * 5 + 11);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
-               radeon_semaphore_free(rdev, &sem, NULL);
+               radeon_sync_free(rdev, &sync, NULL);
                return ERR_PTR(r);
        }
 
-       radeon_semaphore_sync_resv(rdev, sem, resv, false);
-       radeon_semaphore_sync_rings(rdev, sem, ring->idx);
+       radeon_sync_resv(rdev, &sync, resv, false);
+       radeon_sync_rings(rdev, &sync, ring->idx);
 
        for (i = 0; i < num_loops; i++) {
                cur_size_in_dw = size_in_dw;
@@ -153,12 +149,12 @@ struct radeon_fence *evergreen_copy_dma(struct radeon_device *rdev,
        r = radeon_fence_emit(rdev, &fence, ring->idx);
        if (r) {
                radeon_ring_unlock_undo(rdev, ring);
-               radeon_semaphore_free(rdev, &sem, NULL);
+               radeon_sync_free(rdev, &sync, NULL);
                return ERR_PTR(r);
        }
 
        radeon_ring_unlock_commit(rdev, ring, false);
-       radeon_semaphore_free(rdev, &sem, fence);
+       radeon_sync_free(rdev, &sync, fence);
 
        return fence;
 }
index 3faee58946dd0027b67d5d835af50f8de899ec93..360de9f1f4914079d3de3ad0022a50862b934395 100644 (file)
@@ -1373,6 +1373,7 @@ void cayman_fence_ring_emit(struct radeon_device *rdev,
 void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
 {
        struct radeon_ring *ring = &rdev->ring[ib->ring];
+       unsigned vm_id = ib->vm ? ib->vm->ids[ib->ring].id : 0;
        u32 cp_coher_cntl = PACKET3_FULL_CACHE_ENA | PACKET3_TC_ACTION_ENA |
                PACKET3_SH_ACTION_ENA;
 
@@ -1395,15 +1396,14 @@ void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
 #endif
                          (ib->gpu_addr & 0xFFFFFFFC));
        radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFF);
-       radeon_ring_write(ring, ib->length_dw | 
-                         (ib->vm ? (ib->vm->id << 24) : 0));
+       radeon_ring_write(ring, ib->length_dw | (vm_id << 24));
 
        /* flush read cache over gart for this vmid */
        radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3));
        radeon_ring_write(ring, PACKET3_ENGINE_ME | cp_coher_cntl);
        radeon_ring_write(ring, 0xFFFFFFFF);
        radeon_ring_write(ring, 0);
-       radeon_ring_write(ring, ((ib->vm ? ib->vm->id : 0) << 24) | 10); /* poll interval */
+       radeon_ring_write(ring, (vm_id << 24) | 10); /* poll interval */
 }
 
 static void cayman_cp_enable(struct radeon_device *rdev, bool enable)
@@ -2502,15 +2502,11 @@ void cayman_vm_decode_fault(struct radeon_device *rdev,
  * Update the page table base and flush the VM TLB
  * using the CP (cayman-si).
  */
-void cayman_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
+void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
+                    unsigned vm_id, uint64_t pd_addr)
 {
-       struct radeon_ring *ring = &rdev->ring[ridx];
-
-       if (vm == NULL)
-               return;
-
-       radeon_ring_write(ring, PACKET0(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2), 0));
-       radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
+       radeon_ring_write(ring, PACKET0(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2), 0));
+       radeon_ring_write(ring, pd_addr >> 12);
 
        /* flush hdp cache */
        radeon_ring_write(ring, PACKET0(HDP_MEM_COHERENCY_FLUSH_CNTL, 0));
@@ -2518,7 +2514,7 @@ void cayman_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
 
        /* bits 0-7 are the VM contexts0-7 */
        radeon_ring_write(ring, PACKET0(VM_INVALIDATE_REQUEST, 0));
-       radeon_ring_write(ring, 1 << vm->id);
+       radeon_ring_write(ring, 1 << vm_id);
 
        /* sync PFP to ME, otherwise we might get invalid PFP reads */
        radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
index f26f0a9fb522ae4671740a7decd4ec18455656b0..50f88611ff60c832dc59e767543f91f8baf859eb 100644 (file)
@@ -123,6 +123,7 @@ void cayman_dma_ring_ib_execute(struct radeon_device *rdev,
                                struct radeon_ib *ib)
 {
        struct radeon_ring *ring = &rdev->ring[ib->ring];
+       unsigned vm_id = ib->vm ? ib->vm->ids[ib->ring].id : 0;
 
        if (rdev->wb.enabled) {
                u32 next_rptr = ring->wptr + 4;
@@ -140,7 +141,7 @@ void cayman_dma_ring_ib_execute(struct radeon_device *rdev,
         */
        while ((ring->wptr & 7) != 5)
                radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0));
-       radeon_ring_write(ring, DMA_IB_PACKET(DMA_PACKET_INDIRECT_BUFFER, ib->vm ? ib->vm->id : 0, 0));
+       radeon_ring_write(ring, DMA_IB_PACKET(DMA_PACKET_INDIRECT_BUFFER, vm_id, 0));
        radeon_ring_write(ring, (ib->gpu_addr & 0xFFFFFFE0));
        radeon_ring_write(ring, (ib->length_dw << 12) | (upper_32_bits(ib->gpu_addr) & 0xFF));
 
@@ -446,16 +447,12 @@ void cayman_dma_vm_pad_ib(struct radeon_ib *ib)
                ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0);
 }
 
-void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
+void cayman_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
+                        unsigned vm_id, uint64_t pd_addr)
 {
-       struct radeon_ring *ring = &rdev->ring[ridx];
-
-       if (vm == NULL)
-               return;
-
        radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0));
-       radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2));
-       radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
+       radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2)) >> 2));
+       radeon_ring_write(ring, pd_addr >> 12);
 
        /* flush hdp cache */
        radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0));
@@ -465,6 +462,6 @@ void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm
        /* bits 0-7 are the VM contexts0-7 */
        radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0));
        radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2));
-       radeon_ring_write(ring, 1 << vm->id);
+       radeon_ring_write(ring, 1 << vm_id);
 }
 
index 5670b8291285d6827e87abd7a66b447ee774d315..7e5724a12f8b0d067445df96c15f14ba47cdc152 100644 (file)
 #define PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE 0x20
 #define PPSMC_STATEFLAG_DEEPSLEEP_BYPASS   0x40
 
+#define FDO_MODE_HARDWARE 0
+#define FDO_MODE_PIECE_WISE_LINEAR 1
+
+enum FAN_CONTROL {
+       FAN_CONTROL_FUZZY,
+       FAN_CONTROL_TABLE
+};
+
 #define PPSMC_Result_OK             ((uint8_t)0x01)
 #define PPSMC_Result_Failed         ((uint8_t)0xFF)
 
@@ -79,6 +87,8 @@ typedef uint8_t PPSMC_Result;
 #define PPSMC_MSG_DisableCac                ((uint8_t)0x54)
 #define PPSMC_TDPClampingActive             ((uint8_t)0x59)
 #define PPSMC_TDPClampingInactive           ((uint8_t)0x5A)
+#define PPSMC_StartFanControl               ((uint8_t)0x5B)
+#define PPSMC_StopFanControl                ((uint8_t)0x5C)
 #define PPSMC_MSG_NoDisplay                 ((uint8_t)0x5D)
 #define PPSMC_MSG_HasDisplay                ((uint8_t)0x5E)
 #define PPSMC_MSG_UVDPowerOFF               ((uint8_t)0x60)
@@ -106,6 +116,7 @@ typedef uint8_t PPSMC_Result;
 #define PPSMC_MSG_SAMUDPM_SetEnabledMask      ((uint16_t) 0x130)
 #define PPSMC_MSG_MCLKDPM_ForceState          ((uint16_t) 0x131)
 #define PPSMC_MSG_MCLKDPM_NoForcedLevel       ((uint16_t) 0x132)
+#define PPSMC_MSG_Thermal_Cntl_Disable        ((uint16_t) 0x133)
 #define PPSMC_MSG_Voltage_Cntl_Disable        ((uint16_t) 0x135)
 #define PPSMC_MSG_PCIeDPM_Enable              ((uint16_t) 0x136)
 #define PPSMC_MSG_PCIeDPM_Disable             ((uint16_t) 0x13d)
@@ -149,6 +160,10 @@ typedef uint8_t PPSMC_Result;
 #define PPSMC_MSG_MASTER_DeepSleep_ON         ((uint16_t) 0x18F)
 #define PPSMC_MSG_MASTER_DeepSleep_OFF        ((uint16_t) 0x190)
 #define PPSMC_MSG_Remove_DC_Clamp             ((uint16_t) 0x191)
+#define PPSMC_MSG_SetFanPwmMax                ((uint16_t) 0x19A)
+
+#define PPSMC_MSG_ENABLE_THERMAL_DPM          ((uint16_t) 0x19C)
+#define PPSMC_MSG_DISABLE_THERMAL_DPM         ((uint16_t) 0x19D)
 
 #define PPSMC_MSG_API_GetSclkFrequency        ((uint16_t) 0x200)
 #define PPSMC_MSG_API_GetMclkFrequency        ((uint16_t) 0x201)
@@ -157,10 +172,11 @@ typedef uint8_t PPSMC_Result;
 #define PPSMC_MSG_DPM_Config                ((uint32_t) 0x102)
 #define PPSMC_MSG_DPM_ForceState            ((uint32_t) 0x104)
 #define PPSMC_MSG_PG_SIMD_Config            ((uint32_t) 0x108)
-#define PPSMC_MSG_DPM_N_LevelsDisabled      ((uint32_t) 0x112)
+#define PPSMC_MSG_Thermal_Cntl_Enable       ((uint32_t) 0x10a)
 #define PPSMC_MSG_Voltage_Cntl_Enable       ((uint32_t) 0x109)
 #define PPSMC_MSG_VCEPowerOFF               ((uint32_t) 0x10e)
 #define PPSMC_MSG_VCEPowerON                ((uint32_t) 0x10f)
+#define PPSMC_MSG_DPM_N_LevelsDisabled      ((uint32_t) 0x112)
 #define PPSMC_MSG_DCE_RemoveVoltageAdjustment   ((uint32_t) 0x11d)
 #define PPSMC_MSG_DCE_AllowVoltageAdjustment    ((uint32_t) 0x11e)
 #define PPSMC_MSG_EnableBAPM                ((uint32_t) 0x120)
index 2d532996c69795cc129cb4ac6c60a4dfc4b70808..4c2eec49dadc93427bd54336daf4ee0d410fdcc4 100644 (file)
@@ -96,6 +96,14 @@ typedef struct _ATOM_PPLIB_FANTABLE2
     USHORT  usTMax;                          // The max temperature
 } ATOM_PPLIB_FANTABLE2;
 
+typedef struct _ATOM_PPLIB_FANTABLE3
+{
+       ATOM_PPLIB_FANTABLE2 basicTable2;
+       UCHAR ucFanControlMode;
+       USHORT usFanPWMMax;
+       USHORT usFanOutputSensitivity;
+} ATOM_PPLIB_FANTABLE3;
+
 typedef struct _ATOM_PPLIB_EXTENDEDHEADER
 {
     USHORT  usSize;
index 56b02927cd3de5901da653bbea13cfcc7e9858ab..ef5d6066fa5bbb95d40e8ff4ab99d8953d0f61b1 100644 (file)
@@ -2889,31 +2889,27 @@ struct radeon_fence *r600_copy_cpdma(struct radeon_device *rdev,
                                     unsigned num_gpu_pages,
                                     struct reservation_object *resv)
 {
-       struct radeon_semaphore *sem = NULL;
        struct radeon_fence *fence;
+       struct radeon_sync sync;
        int ring_index = rdev->asic->copy.blit_ring_index;
        struct radeon_ring *ring = &rdev->ring[ring_index];
        u32 size_in_bytes, cur_size_in_bytes, tmp;
        int i, num_loops;
        int r = 0;
 
-       r = radeon_semaphore_create(rdev, &sem);
-       if (r) {
-               DRM_ERROR("radeon: moving bo (%d).\n", r);
-               return ERR_PTR(r);
-       }
+       radeon_sync_create(&sync);
 
        size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
        num_loops = DIV_ROUND_UP(size_in_bytes, 0x1fffff);
        r = radeon_ring_lock(rdev, ring, num_loops * 6 + 24);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
-               radeon_semaphore_free(rdev, &sem, NULL);
+               radeon_sync_free(rdev, &sync, NULL);
                return ERR_PTR(r);
        }
 
-       radeon_semaphore_sync_resv(rdev, sem, resv, false);
-       radeon_semaphore_sync_rings(rdev, sem, ring->idx);
+       radeon_sync_resv(rdev, &sync, resv, false);
+       radeon_sync_rings(rdev, &sync, ring->idx);
 
        radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
        radeon_ring_write(ring, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
@@ -2942,12 +2938,12 @@ struct radeon_fence *r600_copy_cpdma(struct radeon_device *rdev,
        r = radeon_fence_emit(rdev, &fence, ring->idx);
        if (r) {
                radeon_ring_unlock_undo(rdev, ring);
-               radeon_semaphore_free(rdev, &sem, NULL);
+               radeon_sync_free(rdev, &sync, NULL);
                return ERR_PTR(r);
        }
 
        radeon_ring_unlock_commit(rdev, ring, false);
-       radeon_semaphore_free(rdev, &sem, fence);
+       radeon_sync_free(rdev, &sync, fence);
 
        return fence;
 }
index cf0df45d455e91ae3a363095dd02dccbb728bab3..d2dd29ab24fa9192d2207c5790035ad0059b0ddd 100644 (file)
@@ -441,31 +441,27 @@ struct radeon_fence *r600_copy_dma(struct radeon_device *rdev,
                                   unsigned num_gpu_pages,
                                   struct reservation_object *resv)
 {
-       struct radeon_semaphore *sem = NULL;
        struct radeon_fence *fence;
+       struct radeon_sync sync;
        int ring_index = rdev->asic->copy.dma_ring_index;
        struct radeon_ring *ring = &rdev->ring[ring_index];
        u32 size_in_dw, cur_size_in_dw;
        int i, num_loops;
        int r = 0;
 
-       r = radeon_semaphore_create(rdev, &sem);
-       if (r) {
-               DRM_ERROR("radeon: moving bo (%d).\n", r);
-               return ERR_PTR(r);
-       }
+       radeon_sync_create(&sync);
 
        size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4;
        num_loops = DIV_ROUND_UP(size_in_dw, 0xFFFE);
        r = radeon_ring_lock(rdev, ring, num_loops * 4 + 8);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
-               radeon_semaphore_free(rdev, &sem, NULL);
+               radeon_sync_free(rdev, &sync, NULL);
                return ERR_PTR(r);
        }
 
-       radeon_semaphore_sync_resv(rdev, sem, resv, false);
-       radeon_semaphore_sync_rings(rdev, sem, ring->idx);
+       radeon_sync_resv(rdev, &sync, resv, false);
+       radeon_sync_rings(rdev, &sync, ring->idx);
 
        for (i = 0; i < num_loops; i++) {
                cur_size_in_dw = size_in_dw;
@@ -484,12 +480,12 @@ struct radeon_fence *r600_copy_dma(struct radeon_device *rdev,
        r = radeon_fence_emit(rdev, &fence, ring->idx);
        if (r) {
                radeon_ring_unlock_undo(rdev, ring);
-               radeon_semaphore_free(rdev, &sem, NULL);
+               radeon_sync_free(rdev, &sync, NULL);
                return ERR_PTR(r);
        }
 
        radeon_ring_unlock_commit(rdev, ring, false);
-       radeon_semaphore_free(rdev, &sem, fence);
+       radeon_sync_free(rdev, &sync, fence);
 
        return fence;
 }
index f6309bd23e0156461f625aa30e8354dbf3a129dd..843b65f46ece168a8694a8a86a974befda12290b 100644 (file)
@@ -811,6 +811,7 @@ union power_info {
 union fan_info {
        struct _ATOM_PPLIB_FANTABLE fan;
        struct _ATOM_PPLIB_FANTABLE2 fan2;
+       struct _ATOM_PPLIB_FANTABLE3 fan3;
 };
 
 static int r600_parse_clk_voltage_dep_table(struct radeon_clock_voltage_dependency_table *radeon_table,
@@ -900,6 +901,14 @@ int r600_parse_extended_power_table(struct radeon_device *rdev)
                        else
                                rdev->pm.dpm.fan.t_max = 10900;
                        rdev->pm.dpm.fan.cycle_delay = 100000;
+                       if (fan_info->fan.ucFanTableFormat >= 3) {
+                               rdev->pm.dpm.fan.control_mode = fan_info->fan3.ucFanControlMode;
+                               rdev->pm.dpm.fan.default_max_fan_pwm =
+                                       le16_to_cpu(fan_info->fan3.usFanPWMMax);
+                               rdev->pm.dpm.fan.default_fan_output_sensitivity = 4836;
+                               rdev->pm.dpm.fan.fan_output_sensitivity =
+                                       le16_to_cpu(fan_info->fan3.usFanOutputSensitivity);
+                       }
                        rdev->pm.dpm.fan.ucode_fan_control = true;
                }
        }
@@ -1256,7 +1265,7 @@ int r600_parse_extended_power_table(struct radeon_device *rdev)
                                        (mode_info->atom_context->bios + data_offset +
                                         le16_to_cpu(ext_hdr->usPowerTuneTableOffset));
                                rdev->pm.dpm.dyn_state.cac_tdp_table->maximum_power_delivery_limit =
-                                       ppt->usMaximumPowerDeliveryLimit;
+                                       le16_to_cpu(ppt->usMaximumPowerDeliveryLimit);
                                pt = &ppt->power_tune_table;
                        } else {
                                ATOM_PPLIB_POWERTUNE_Table *ppt = (ATOM_PPLIB_POWERTUNE_Table *)
index 46b9d2a03018d854cb07c72d3eaeee9aa8f4a10d..bd499d749bc980d96b49472d7206665dfb3ab175 100644 (file)
@@ -96,6 +96,9 @@
 #define R600_TEMP_RANGE_MIN (90 * 1000)
 #define R600_TEMP_RANGE_MAX (120 * 1000)
 
+#define FDO_PWM_MODE_STATIC  1
+#define FDO_PWM_MODE_STATIC_RPM 5
+
 enum r600_power_level {
        R600_POWER_LEVEL_LOW = 0,
        R600_POWER_LEVEL_MEDIUM = 1,
index a9717b3fbf1b4bd77417c38c29ac2c577179e947..3207bb60715e961b72f083a0fbbb034a3ee0b2a2 100644 (file)
@@ -150,9 +150,6 @@ extern int radeon_backlight;
 /* number of hw syncs before falling back on blocking */
 #define RADEON_NUM_SYNCS                       4
 
-/* number of hw syncs before falling back on blocking */
-#define RADEON_NUM_SYNCS                       4
-
 /* hardcode those limit for now */
 #define RADEON_VA_IB_OFFSET                    (1 << 20)
 #define RADEON_VA_RESERVED_SIZE                        (8 << 20)
@@ -363,14 +360,15 @@ struct radeon_fence_driver {
 };
 
 struct radeon_fence {
-       struct fence base;
+       struct fence            base;
 
-       struct radeon_device            *rdev;
-       uint64_t                        seq;
+       struct radeon_device    *rdev;
+       uint64_t                seq;
        /* RB, DMA, etc. */
-       unsigned                        ring;
+       unsigned                ring;
+       bool                    is_vm_update;
 
-       wait_queue_t                    fence_wake;
+       wait_queue_t            fence_wake;
 };
 
 int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring);
@@ -458,6 +456,7 @@ struct radeon_bo_va {
        struct list_head                bo_list;
        uint32_t                        flags;
        uint64_t                        addr;
+       struct radeon_fence             *last_pt_update;
        unsigned                        ref_count;
 
        /* protected by vm mutex */
@@ -474,7 +473,7 @@ struct radeon_bo {
        struct list_head                list;
        /* Protected by tbo.reserved */
        u32                             initial_domain;
-       struct ttm_place                placements[3];
+       struct ttm_place                placements[4];
        struct ttm_placement            placement;
        struct ttm_buffer_object        tbo;
        struct ttm_bo_kmap_obj          kmap;
@@ -576,10 +575,9 @@ int radeon_mode_dumb_mmap(struct drm_file *filp,
  * Semaphores.
  */
 struct radeon_semaphore {
-       struct radeon_sa_bo             *sa_bo;
-       signed                          waiters;
-       uint64_t                        gpu_addr;
-       struct radeon_fence             *sync_to[RADEON_NUM_RINGS];
+       struct radeon_sa_bo     *sa_bo;
+       signed                  waiters;
+       uint64_t                gpu_addr;
 };
 
 int radeon_semaphore_create(struct radeon_device *rdev,
@@ -588,19 +586,32 @@ bool radeon_semaphore_emit_signal(struct radeon_device *rdev, int ring,
                                  struct radeon_semaphore *semaphore);
 bool radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring,
                                struct radeon_semaphore *semaphore);
-void radeon_semaphore_sync_fence(struct radeon_semaphore *semaphore,
-                                struct radeon_fence *fence);
-int radeon_semaphore_sync_resv(struct radeon_device *rdev,
-                              struct radeon_semaphore *semaphore,
-                              struct reservation_object *resv,
-                              bool shared);
-int radeon_semaphore_sync_rings(struct radeon_device *rdev,
-                               struct radeon_semaphore *semaphore,
-                               int waiting_ring);
 void radeon_semaphore_free(struct radeon_device *rdev,
                           struct radeon_semaphore **semaphore,
                           struct radeon_fence *fence);
 
+/*
+ * Synchronization
+ */
+struct radeon_sync {
+       struct radeon_semaphore *semaphores[RADEON_NUM_SYNCS];
+       struct radeon_fence     *sync_to[RADEON_NUM_RINGS];
+       struct radeon_fence     *last_vm_update;
+};
+
+void radeon_sync_create(struct radeon_sync *sync);
+void radeon_sync_fence(struct radeon_sync *sync,
+                      struct radeon_fence *fence);
+int radeon_sync_resv(struct radeon_device *rdev,
+                    struct radeon_sync *sync,
+                    struct reservation_object *resv,
+                    bool shared);
+int radeon_sync_rings(struct radeon_device *rdev,
+                     struct radeon_sync *sync,
+                     int waiting_ring);
+void radeon_sync_free(struct radeon_device *rdev, struct radeon_sync *sync,
+                     struct radeon_fence *fence);
+
 /*
  * GART structures, functions & helpers
  */
@@ -701,6 +712,10 @@ struct radeon_doorbell {
 
 int radeon_doorbell_get(struct radeon_device *rdev, u32 *page);
 void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell);
+void radeon_doorbell_get_kfd_info(struct radeon_device *rdev,
+                                 phys_addr_t *aperture_base,
+                                 size_t *aperture_size,
+                                 size_t *start_offset);
 
 /*
  * IRQS.
@@ -814,7 +829,7 @@ struct radeon_ib {
        struct radeon_fence             *fence;
        struct radeon_vm                *vm;
        bool                            is_const_ib;
-       struct radeon_semaphore         *semaphore;
+       struct radeon_sync              sync;
 };
 
 struct radeon_ring {
@@ -891,33 +906,37 @@ struct radeon_vm_pt {
        uint64_t                        addr;
 };
 
+struct radeon_vm_id {
+       unsigned                id;
+       uint64_t                pd_gpu_addr;
+       /* last flushed PD/PT update */
+       struct radeon_fence     *flushed_updates;
+       /* last use of vmid */
+       struct radeon_fence     *last_id_use;
+};
+
 struct radeon_vm {
-       struct rb_root                  va;
-       unsigned                        id;
+       struct mutex            mutex;
+
+       struct rb_root          va;
 
        /* BOs moved, but not yet updated in the PT */
-       struct list_head                invalidated;
+       struct list_head        invalidated;
 
        /* BOs freed, but not yet updated in the PT */
-       struct list_head                freed;
+       struct list_head        freed;
 
        /* contains the page directory */
-       struct radeon_bo                *page_directory;
-       uint64_t                        pd_gpu_addr;
-       unsigned                        max_pde_used;
+       struct radeon_bo        *page_directory;
+       unsigned                max_pde_used;
 
        /* array of page tables, one for each page directory entry */
-       struct radeon_vm_pt             *page_tables;
+       struct radeon_vm_pt     *page_tables;
 
-       struct radeon_bo_va             *ib_bo_va;
+       struct radeon_bo_va     *ib_bo_va;
 
-       struct mutex                    mutex;
-       /* last fence for cs using this vm */
-       struct radeon_fence             *fence;
-       /* last flush or NULL if we still need to flush */
-       struct radeon_fence             *last_flush;
-       /* last use of vmid */
-       struct radeon_fence             *last_id_use;
+       /* for id and flush management per ring */
+       struct radeon_vm_id     ids[RADEON_NUM_RINGS];
 };
 
 struct radeon_vm_manager {
@@ -1490,6 +1509,10 @@ struct radeon_dpm_fan {
        u8 t_hyst;
        u32 cycle_delay;
        u16 t_max;
+       u8 control_mode;
+       u16 default_max_fan_pwm;
+       u16 default_fan_output_sensitivity;
+       u16 fan_output_sensitivity;
        bool ucode_fan_control;
 };
 
@@ -1623,6 +1646,11 @@ struct radeon_pm {
        /* internal thermal controller on rv6xx+ */
        enum radeon_int_thermal_type int_thermal_type;
        struct device           *int_hwmon_dev;
+       /* fan control parameters */
+       bool                    no_fan;
+       u8                      fan_pulses_per_revolution;
+       u8                      fan_min_rpm;
+       u8                      fan_max_rpm;
        /* dpm */
        bool                    dpm_enabled;
        struct radeon_dpm       dpm;
@@ -1785,7 +1813,8 @@ struct radeon_asic_ring {
        void (*hdp_flush)(struct radeon_device *rdev, struct radeon_ring *ring);
        bool (*emit_semaphore)(struct radeon_device *rdev, struct radeon_ring *cp,
                               struct radeon_semaphore *semaphore, bool emit_wait);
-       void (*vm_flush)(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
+       void (*vm_flush)(struct radeon_device *rdev, struct radeon_ring *ring,
+                        unsigned vm_id, uint64_t pd_addr);
 
        /* testing functions */
        int (*ring_test)(struct radeon_device *rdev, struct radeon_ring *cp);
@@ -2388,6 +2417,8 @@ struct radeon_device {
        struct radeon_atcs              atcs;
        /* srbm instance registers */
        struct mutex                    srbm_mutex;
+       /* GRBM index mutex. Protects concurrents access to GRBM index */
+       struct mutex                    grbm_idx_mutex;
        /* clock, powergating flags */
        u32 cg_flags;
        u32 pg_flags;
@@ -2400,6 +2431,10 @@ struct radeon_device {
        u64 vram_pin_size;
        u64 gart_pin_size;
 
+       /* amdkfd interface */
+       struct kfd_dev          *kfd;
+       struct radeon_sa_manager        kfd_bo;
+
        struct mutex    mn_lock;
        DECLARE_HASHTABLE(mn_hash, 7);
 };
@@ -2831,7 +2866,7 @@ static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v)
 #define radeon_ring_ib_execute(rdev, r, ib) (rdev)->asic->ring[(r)]->ib_execute((rdev), (ib))
 #define radeon_ring_ib_parse(rdev, r, ib) (rdev)->asic->ring[(r)]->ib_parse((rdev), (ib))
 #define radeon_ring_is_lockup(rdev, r, cp) (rdev)->asic->ring[(r)]->is_lockup((rdev), (cp))
-#define radeon_ring_vm_flush(rdev, r, vm) (rdev)->asic->ring[(r)]->vm_flush((rdev), (r), (vm))
+#define radeon_ring_vm_flush(rdev, r, vm_id, pd_addr) (rdev)->asic->ring[(r)->idx]->vm_flush((rdev), (r), (vm_id), (pd_addr))
 #define radeon_ring_get_rptr(rdev, r) (rdev)->asic->ring[(r)->idx]->get_rptr((rdev), (r))
 #define radeon_ring_get_wptr(rdev, r) (rdev)->asic->ring[(r)->idx]->get_wptr((rdev), (r))
 #define radeon_ring_set_wptr(rdev, r) (rdev)->asic->ring[(r)->idx]->set_wptr((rdev), (r))
@@ -2947,7 +2982,7 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
                                       struct radeon_vm *vm, int ring);
 void radeon_vm_flush(struct radeon_device *rdev,
                      struct radeon_vm *vm,
-                     int ring);
+                    int ring, struct radeon_fence *fence);
 void radeon_vm_fence(struct radeon_device *rdev,
                     struct radeon_vm *vm,
                     struct radeon_fence *fence);
index d8ace5b28a5b2e1455b5776129022300b3d1be3e..2a45d548d5ece5d9cd1cdad32d64fb3808b0c6fd 100644 (file)
@@ -599,7 +599,8 @@ int cayman_asic_reset(struct radeon_device *rdev);
 void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
 int cayman_vm_init(struct radeon_device *rdev);
 void cayman_vm_fini(struct radeon_device *rdev);
-void cayman_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
+void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
+                    unsigned vm_id, uint64_t pd_addr);
 uint32_t cayman_vm_page_flags(struct radeon_device *rdev, uint32_t flags);
 int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
 int evergreen_dma_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
@@ -624,7 +625,8 @@ void cayman_dma_vm_set_pages(struct radeon_device *rdev,
                             uint32_t incr, uint32_t flags);
 void cayman_dma_vm_pad_ib(struct radeon_ib *ib);
 
-void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
+void cayman_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
+                        unsigned vm_id, uint64_t pd_addr);
 
 u32 cayman_gfx_get_rptr(struct radeon_device *rdev,
                        struct radeon_ring *ring);
@@ -699,7 +701,8 @@ int si_irq_set(struct radeon_device *rdev);
 int si_irq_process(struct radeon_device *rdev);
 int si_vm_init(struct radeon_device *rdev);
 void si_vm_fini(struct radeon_device *rdev);
-void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
+void si_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
+                unsigned vm_id, uint64_t pd_addr);
 int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
 struct radeon_fence *si_copy_dma(struct radeon_device *rdev,
                                 uint64_t src_offset, uint64_t dst_offset,
@@ -721,7 +724,8 @@ void si_dma_vm_set_pages(struct radeon_device *rdev,
                         uint64_t addr, unsigned count,
                         uint32_t incr, uint32_t flags);
 
-void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
+void si_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
+                    unsigned vm_id, uint64_t pd_addr);
 u32 si_get_xclk(struct radeon_device *rdev);
 uint64_t si_get_gpu_clock_counter(struct radeon_device *rdev);
 int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
@@ -793,7 +797,8 @@ int cik_irq_set(struct radeon_device *rdev);
 int cik_irq_process(struct radeon_device *rdev);
 int cik_vm_init(struct radeon_device *rdev);
 void cik_vm_fini(struct radeon_device *rdev);
-void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
+void cik_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
+                 unsigned vm_id, uint64_t pd_addr);
 
 void cik_sdma_vm_copy_pages(struct radeon_device *rdev,
                            struct radeon_ib *ib,
@@ -811,7 +816,8 @@ void cik_sdma_vm_set_pages(struct radeon_device *rdev,
                           uint32_t incr, uint32_t flags);
 void cik_sdma_vm_pad_ib(struct radeon_ib *ib);
 
-void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
+void cik_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
+                     unsigned vm_id, uint64_t pd_addr);
 int cik_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
 u32 cik_gfx_get_rptr(struct radeon_device *rdev,
                     struct radeon_ring *ring);
index df69b92ba164158cc5e7ae79f7b59db65305dd49..dbc94f3002972dfb9319289e133bbc5ca2d985c6 100644 (file)
@@ -196,8 +196,8 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev)
        }
 }
 
-static struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rdev,
-                                                u8 id)
+struct radeon_gpio_rec radeon_atombios_lookup_gpio(struct radeon_device *rdev,
+                                                  u8 id)
 {
        struct atom_context *ctx = rdev->mode_info.atom_context;
        struct radeon_gpio_rec gpio;
@@ -221,6 +221,7 @@ static struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rdev,
                        if (id == pin->ucGPIO_ID) {
                                gpio.id = pin->ucGPIO_ID;
                                gpio.reg = le16_to_cpu(pin->usGpioPin_AIndex) * 4;
+                               gpio.shift = pin->ucGpioPinBitShift;
                                gpio.mask = (1 << pin->ucGpioPinBitShift);
                                gpio.valid = true;
                                break;
@@ -801,7 +802,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
                                                                hpd_record =
                                                                        (ATOM_HPD_INT_RECORD *)
                                                                        record;
-                                                               gpio = radeon_lookup_gpio(rdev,
+                                                               gpio = radeon_atombios_lookup_gpio(rdev,
                                                                                          hpd_record->ucHPDIntGPIOID);
                                                                hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio);
                                                                hpd.plugged_state = hpd_record->ucPlugged_PinState;
@@ -2128,7 +2129,7 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)
                                rdev->pm.power_state[state_index].clock_info[0].voltage.type =
                                        VOLTAGE_GPIO;
                                rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
-                                       radeon_lookup_gpio(rdev,
+                                       radeon_atombios_lookup_gpio(rdev,
                                                           power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex);
                                if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
                                        rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
@@ -2164,7 +2165,7 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)
                                rdev->pm.power_state[state_index].clock_info[0].voltage.type =
                                        VOLTAGE_GPIO;
                                rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
-                                       radeon_lookup_gpio(rdev,
+                                       radeon_atombios_lookup_gpio(rdev,
                                                           power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex);
                                if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
                                        rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
@@ -2200,7 +2201,7 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)
                                rdev->pm.power_state[state_index].clock_info[0].voltage.type =
                                        VOLTAGE_GPIO;
                                rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
-                                       radeon_lookup_gpio(rdev,
+                                       radeon_atombios_lookup_gpio(rdev,
                                                           power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex);
                                if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
                                        rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
@@ -2248,6 +2249,14 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r
 
        /* add the i2c bus for thermal/fan chip */
        if (controller->ucType > 0) {
+               if (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN)
+                       rdev->pm.no_fan = true;
+               rdev->pm.fan_pulses_per_revolution =
+                       controller->ucFanParameters & ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
+               if (rdev->pm.fan_pulses_per_revolution) {
+                       rdev->pm.fan_min_rpm = controller->ucFanMinRPM;
+                       rdev->pm.fan_max_rpm = controller->ucFanMaxRPM;
+               }
                if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) {
                        DRM_INFO("Internal thermal controller %s fan control\n",
                                 (controller->ucFanParameters &
index 300c4b3d4669426d5085d7e5d2e52e23321988d3..26baa9c05f6c49ac40e2a238a6079fa8e0e40920 100644 (file)
@@ -322,6 +322,12 @@ static void radeon_connector_get_edid(struct drm_connector *connector)
        }
 
        if (!radeon_connector->edid) {
+               /* don't fetch the edid from the vbios if ddc fails and runpm is
+                * enabled so we report disconnected.
+                */
+               if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
+                       return;
+
                if (rdev->is_atom_bios) {
                        /* some laptops provide a hardcoded edid in rom for LCDs */
                        if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) ||
@@ -826,6 +832,8 @@ static int radeon_lvds_mode_valid(struct drm_connector *connector,
 static enum drm_connector_status
 radeon_lvds_detect(struct drm_connector *connector, bool force)
 {
+       struct drm_device *dev = connector->dev;
+       struct radeon_device *rdev = dev->dev_private;
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
        struct drm_encoder *encoder = radeon_best_single_encoder(connector);
        enum drm_connector_status ret = connector_status_disconnected;
@@ -842,7 +850,11 @@ radeon_lvds_detect(struct drm_connector *connector, bool force)
                /* check if panel is valid */
                if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
                        ret = connector_status_connected;
-
+               /* don't fetch the edid from the vbios if ddc fails and runpm is
+                * enabled so we report disconnected.
+                */
+               if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
+                       ret = connector_status_disconnected;
        }
 
        /* check for edid as well */
@@ -1589,6 +1601,11 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
                        /* check if panel is valid */
                        if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
                                ret = connector_status_connected;
+                       /* don't fetch the edid from the vbios if ddc fails and runpm is
+                        * enabled so we report disconnected.
+                        */
+                       if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
+                               ret = connector_status_disconnected;
                }
                /* eDP is always DP */
                radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
index a3e7aed7e68075f5418ad83e80217d7f6206d89d..75f22e5e999fc455565f9bad0a7e2c2322199a9f 100644 (file)
@@ -260,8 +260,8 @@ static int radeon_cs_sync_rings(struct radeon_cs_parser *p)
                        continue;
 
                resv = p->relocs[i].robj->tbo.resv;
-               r = radeon_semaphore_sync_resv(p->rdev, p->ib.semaphore, resv,
-                                              p->relocs[i].tv.shared);
+               r = radeon_sync_resv(p->rdev, &p->ib.sync, resv,
+                                    p->relocs[i].tv.shared);
 
                if (r)
                        break;
@@ -285,9 +285,7 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
        INIT_LIST_HEAD(&p->validated);
        p->idx = 0;
        p->ib.sa_bo = NULL;
-       p->ib.semaphore = NULL;
        p->const_ib.sa_bo = NULL;
-       p->const_ib.semaphore = NULL;
        p->chunk_ib_idx = -1;
        p->chunk_relocs_idx = -1;
        p->chunk_flags_idx = -1;
@@ -507,6 +505,9 @@ static int radeon_bo_vm_update_pte(struct radeon_cs_parser *p,
        if (r)
                return r;
 
+       radeon_sync_resv(p->rdev, &p->ib.sync, vm->page_directory->tbo.resv,
+                        true);
+
        r = radeon_vm_clear_freed(rdev, vm);
        if (r)
                return r;
@@ -538,6 +539,8 @@ static int radeon_bo_vm_update_pte(struct radeon_cs_parser *p,
                r = radeon_vm_bo_update(rdev, bo_va, &bo->tbo.mem);
                if (r)
                        return r;
+
+               radeon_sync_fence(&p->ib.sync, bo_va->last_pt_update);
        }
 
        return radeon_vm_clear_invalids(rdev, vm);
@@ -582,7 +585,6 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
                        DRM_ERROR("Failed to sync rings: %i\n", r);
                goto out;
        }
-       radeon_semaphore_sync_fence(parser->ib.semaphore, vm->fence);
 
        if ((rdev->family >= CHIP_TAHITI) &&
            (parser->chunk_const_ib_idx != -1)) {
index 9630e8d95fb40655df4ceefd18e5015ca47194c6..85f38ee1188887722f70ed2e6d9886fcd9193e54 100644 (file)
@@ -117,106 +117,7 @@ static void radeon_show_cursor(struct drm_crtc *crtc)
        }
 }
 
-static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj,
-                             uint64_t gpu_addr)
-{
-       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
-       struct radeon_device *rdev = crtc->dev->dev_private;
-
-       if (ASIC_IS_DCE4(rdev)) {
-               WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
-                      upper_32_bits(gpu_addr));
-               WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
-                      gpu_addr & 0xffffffff);
-       } else if (ASIC_IS_AVIVO(rdev)) {
-               if (rdev->family >= CHIP_RV770) {
-                       if (radeon_crtc->crtc_id)
-                               WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
-                       else
-                               WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
-               }
-               WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
-                      gpu_addr & 0xffffffff);
-       } else {
-               radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr;
-               /* offset is from DISP(2)_BASE_ADDRESS */
-               WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset);
-       }
-}
-
-int radeon_crtc_cursor_set(struct drm_crtc *crtc,
-                          struct drm_file *file_priv,
-                          uint32_t handle,
-                          uint32_t width,
-                          uint32_t height)
-{
-       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
-       struct radeon_device *rdev = crtc->dev->dev_private;
-       struct drm_gem_object *obj;
-       struct radeon_bo *robj;
-       uint64_t gpu_addr;
-       int ret;
-
-       if (!handle) {
-               /* turn off cursor */
-               radeon_hide_cursor(crtc);
-               obj = NULL;
-               goto unpin;
-       }
-
-       if ((width > radeon_crtc->max_cursor_width) ||
-           (height > radeon_crtc->max_cursor_height)) {
-               DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
-               return -EINVAL;
-       }
-
-       obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
-       if (!obj) {
-               DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
-               return -ENOENT;
-       }
-
-       robj = gem_to_radeon_bo(obj);
-       ret = radeon_bo_reserve(robj, false);
-       if (unlikely(ret != 0))
-               goto fail;
-       /* Only 27 bit offset for legacy cursor */
-       ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM,
-                                      ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
-                                      &gpu_addr);
-       radeon_bo_unreserve(robj);
-       if (ret)
-               goto fail;
-
-       radeon_crtc->cursor_width = width;
-       radeon_crtc->cursor_height = height;
-
-       radeon_lock_cursor(crtc, true);
-       radeon_set_cursor(crtc, obj, gpu_addr);
-       radeon_show_cursor(crtc);
-       radeon_lock_cursor(crtc, false);
-
-unpin:
-       if (radeon_crtc->cursor_bo) {
-               robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
-               ret = radeon_bo_reserve(robj, false);
-               if (likely(ret == 0)) {
-                       radeon_bo_unpin(robj);
-                       radeon_bo_unreserve(robj);
-               }
-               drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo);
-       }
-
-       radeon_crtc->cursor_bo = obj;
-       return 0;
-fail:
-       drm_gem_object_unreference_unlocked(obj);
-
-       return ret;
-}
-
-int radeon_crtc_cursor_move(struct drm_crtc *crtc,
-                           int x, int y)
+static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
 {
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
        struct radeon_device *rdev = crtc->dev->dev_private;
@@ -281,7 +182,6 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
                }
        }
 
-       radeon_lock_cursor(crtc, true);
        if (ASIC_IS_DCE4(rdev)) {
                WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
                WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
@@ -308,7 +208,134 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
                WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset +
                                                                      (yorigin * 256)));
        }
+
+       radeon_crtc->cursor_x = x;
+       radeon_crtc->cursor_y = y;
+
+       return 0;
+}
+
+int radeon_crtc_cursor_move(struct drm_crtc *crtc,
+                           int x, int y)
+{
+       int ret;
+
+       radeon_lock_cursor(crtc, true);
+       ret = radeon_cursor_move_locked(crtc, x, y);
+       radeon_lock_cursor(crtc, false);
+
+       return ret;
+}
+
+static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj,
+                             uint64_t gpu_addr, int hot_x, int hot_y)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct radeon_device *rdev = crtc->dev->dev_private;
+
+       if (ASIC_IS_DCE4(rdev)) {
+               WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
+                      upper_32_bits(gpu_addr));
+               WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+                      gpu_addr & 0xffffffff);
+       } else if (ASIC_IS_AVIVO(rdev)) {
+               if (rdev->family >= CHIP_RV770) {
+                       if (radeon_crtc->crtc_id)
+                               WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
+                       else
+                               WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
+               }
+               WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+                      gpu_addr & 0xffffffff);
+       } else {
+               radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr;
+               /* offset is from DISP(2)_BASE_ADDRESS */
+               WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset);
+       }
+
+       if (hot_x != radeon_crtc->cursor_hot_x ||
+           hot_y != radeon_crtc->cursor_hot_y) {
+               int x, y;
+
+               x = radeon_crtc->cursor_x + radeon_crtc->cursor_hot_x - hot_x;
+               y = radeon_crtc->cursor_y + radeon_crtc->cursor_hot_y - hot_y;
+
+               radeon_cursor_move_locked(crtc, x, y);
+
+               radeon_crtc->cursor_hot_x = hot_x;
+               radeon_crtc->cursor_hot_y = hot_y;
+       }
+}
+
+int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
+                           struct drm_file *file_priv,
+                           uint32_t handle,
+                           uint32_t width,
+                           uint32_t height,
+                           int32_t hot_x,
+                           int32_t hot_y)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct radeon_device *rdev = crtc->dev->dev_private;
+       struct drm_gem_object *obj;
+       struct radeon_bo *robj;
+       uint64_t gpu_addr;
+       int ret;
+
+       if (!handle) {
+               /* turn off cursor */
+               radeon_hide_cursor(crtc);
+               obj = NULL;
+               goto unpin;
+       }
+
+       if ((width > radeon_crtc->max_cursor_width) ||
+           (height > radeon_crtc->max_cursor_height)) {
+               DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
+               return -EINVAL;
+       }
+
+       obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
+       if (!obj) {
+               DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
+               return -ENOENT;
+       }
+
+       robj = gem_to_radeon_bo(obj);
+       ret = radeon_bo_reserve(robj, false);
+       if (unlikely(ret != 0))
+               goto fail;
+       /* Only 27 bit offset for legacy cursor */
+       ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM,
+                                      ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
+                                      &gpu_addr);
+       radeon_bo_unreserve(robj);
+       if (ret)
+               goto fail;
+
+       radeon_crtc->cursor_width = width;
+       radeon_crtc->cursor_height = height;
+
+       radeon_lock_cursor(crtc, true);
+       radeon_set_cursor(crtc, obj, gpu_addr, hot_x, hot_y);
+       radeon_show_cursor(crtc);
        radeon_lock_cursor(crtc, false);
 
+unpin:
+       if (radeon_crtc->cursor_bo) {
+               robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
+               ret = radeon_bo_reserve(robj, false);
+               if (likely(ret == 0)) {
+                       radeon_bo_unpin(robj);
+                       radeon_bo_unreserve(robj);
+               }
+               drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo);
+       }
+
+       radeon_crtc->cursor_bo = obj;
        return 0;
+fail:
+       drm_gem_object_unreference_unlocked(obj);
+
+       return ret;
 }
index 995a8b1770ddb9871c989c9428a554c313dbc5e9..0ec65168f331c73bcbfff24ee719cd6f98790602 100644 (file)
@@ -377,6 +377,37 @@ void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell)
                __clear_bit(doorbell, rdev->doorbell.used);
 }
 
+/**
+ * radeon_doorbell_get_kfd_info - Report doorbell configuration required to
+ *                                setup KFD
+ *
+ * @rdev: radeon_device pointer
+ * @aperture_base: output returning doorbell aperture base physical address
+ * @aperture_size: output returning doorbell aperture size in bytes
+ * @start_offset: output returning # of doorbell bytes reserved for radeon.
+ *
+ * Radeon and the KFD share the doorbell aperture. Radeon sets it up,
+ * takes doorbells required for its own rings and reports the setup to KFD.
+ * Radeon reserved doorbells are at the start of the doorbell aperture.
+ */
+void radeon_doorbell_get_kfd_info(struct radeon_device *rdev,
+                                 phys_addr_t *aperture_base,
+                                 size_t *aperture_size,
+                                 size_t *start_offset)
+{
+       /* The first num_doorbells are used by radeon.
+        * KFD takes whatever's left in the aperture. */
+       if (rdev->doorbell.size > rdev->doorbell.num_doorbells * sizeof(u32)) {
+               *aperture_base = rdev->doorbell.base;
+               *aperture_size = rdev->doorbell.size;
+               *start_offset = rdev->doorbell.num_doorbells * sizeof(u32);
+       } else {
+               *aperture_base = 0;
+               *aperture_size = 0;
+               *start_offset = 0;
+       }
+}
+
 /*
  * radeon_wb_*()
  * Writeback is the the method by which the the GPU updates special pages
@@ -1273,6 +1304,7 @@ int radeon_device_init(struct radeon_device *rdev,
        mutex_init(&rdev->pm.mutex);
        mutex_init(&rdev->gpu_clock_mutex);
        mutex_init(&rdev->srbm_mutex);
+       mutex_init(&rdev->grbm_idx_mutex);
        init_rwsem(&rdev->pm.mclk_lock);
        init_rwsem(&rdev->exclusive_lock);
        init_waitqueue_head(&rdev->irq.vblank_queue);
index f1b0fa1285bb6f5e19a970164c647431f5409293..102116902a070f728c434a8ee67215ede0cffb70 100644 (file)
@@ -635,7 +635,7 @@ radeon_crtc_set_config(struct drm_mode_set *set)
        return ret;
 }
 static const struct drm_crtc_funcs radeon_crtc_funcs = {
-       .cursor_set = radeon_crtc_cursor_set,
+       .cursor_set2 = radeon_crtc_cursor_set2,
        .cursor_move = radeon_crtc_cursor_move,
        .gamma_set = radeon_crtc_gamma_set,
        .set_config = radeon_crtc_set_config,
index dcffa30ee2db3d2b990abc4089967c204984be5d..4f50fb0e3d93448034191821496d299290bbc5a6 100644 (file)
@@ -41,6 +41,8 @@
 #include <drm/drm_gem.h>
 
 #include "drm_crtc_helper.h"
+#include "radeon_kfd.h"
+
 /*
  * KMS wrapper.
  * - 2.0.0 - initial interface
@@ -654,12 +656,15 @@ static int __init radeon_init(void)
 #endif
        }
 
+       radeon_kfd_init();
+
        /* let modprobe override vga console setting */
        return drm_pci_init(driver, pdriver);
 }
 
 static void __exit radeon_exit(void)
 {
+       radeon_kfd_fini();
        drm_pci_exit(driver, pdriver);
        radeon_unregister_atpx_handler();
 }
index 9a19e52cc655bf8b3c697a7116e52e81b8060096..6b670b0bc47bb9dca0238ef35dcff1cc2f686c34 100644 (file)
@@ -179,6 +179,9 @@ static void radeon_encoder_add_backlight(struct radeon_encoder *radeon_encoder,
                    (rdev->pdev->subsystem_vendor == 0x1734) &&
                    (rdev->pdev->subsystem_device == 0x1107))
                        use_bl = false;
+               /* disable native backlight control on older asics */
+               else if (rdev->family < CHIP_R600)
+                       use_bl = false;
                else
                        use_bl = true;
        }
index 995167025282a13ff7fdbbe7a1555f0d228a751b..d13d1b5a859f5b4d6aa69adc18cf85a2375398d1 100644 (file)
@@ -140,6 +140,7 @@ int radeon_fence_emit(struct radeon_device *rdev,
        (*fence)->rdev = rdev;
        (*fence)->seq = seq;
        (*fence)->ring = ring;
+       (*fence)->is_vm_update = false;
        fence_init(&(*fence)->base, &radeon_fence_ops,
                   &rdev->fence_queue.lock, rdev->fence_context + ring, seq);
        radeon_fence_ring_emit(rdev, ring, *fence);
index c194497aa586e16c5c17776d5baa5959f3eac7c5..12cfaeac12056182c46223c3b4d3d05c3b0be876 100644 (file)
@@ -394,9 +394,10 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
        return r;
 }
 
-int radeon_mode_dumb_mmap(struct drm_file *filp,
-                         struct drm_device *dev,
-                         uint32_t handle, uint64_t *offset_p)
+static int radeon_mode_mmap(struct drm_file *filp,
+                           struct drm_device *dev,
+                           uint32_t handle, bool dumb,
+                           uint64_t *offset_p)
 {
        struct drm_gem_object *gobj;
        struct radeon_bo *robj;
@@ -405,6 +406,14 @@ int radeon_mode_dumb_mmap(struct drm_file *filp,
        if (gobj == NULL) {
                return -ENOENT;
        }
+
+       /*
+        * We don't allow dumb mmaps on objects created using another
+        * interface.
+        */
+       WARN_ONCE(dumb && !(gobj->dumb || gobj->import_attach),
+               "Illegal dumb map of GPU buffer.\n");
+
        robj = gem_to_radeon_bo(gobj);
        if (radeon_ttm_tt_has_userptr(robj->tbo.ttm)) {
                drm_gem_object_unreference_unlocked(gobj);
@@ -415,12 +424,20 @@ int radeon_mode_dumb_mmap(struct drm_file *filp,
        return 0;
 }
 
+int radeon_mode_dumb_mmap(struct drm_file *filp,
+                         struct drm_device *dev,
+                         uint32_t handle, uint64_t *offset_p)
+{
+       return radeon_mode_mmap(filp, dev, handle, true, offset_p);
+}
+
 int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data,
                          struct drm_file *filp)
 {
        struct drm_radeon_gem_mmap *args = data;
 
-       return radeon_mode_dumb_mmap(filp, dev, args->handle, &args->addr_ptr);
+       return radeon_mode_mmap(filp, dev, args->handle, false,
+                               &args->addr_ptr);
 }
 
 int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
@@ -518,6 +535,68 @@ out:
        return r;
 }
 
+/**
+ * radeon_gem_va_update_vm -update the bo_va in its VM
+ *
+ * @rdev: radeon_device pointer
+ * @bo_va: bo_va to update
+ *
+ * Update the bo_va directly after setting it's address. Errors are not
+ * vital here, so they are not reported back to userspace.
+ */
+static void radeon_gem_va_update_vm(struct radeon_device *rdev,
+                                   struct radeon_bo_va *bo_va)
+{
+       struct ttm_validate_buffer tv, *entry;
+       struct radeon_cs_reloc *vm_bos;
+       struct ww_acquire_ctx ticket;
+       struct list_head list;
+       unsigned domain;
+       int r;
+
+       INIT_LIST_HEAD(&list);
+
+       tv.bo = &bo_va->bo->tbo;
+       tv.shared = true;
+       list_add(&tv.head, &list);
+
+       vm_bos = radeon_vm_get_bos(rdev, bo_va->vm, &list);
+       if (!vm_bos)
+               return;
+
+       r = ttm_eu_reserve_buffers(&ticket, &list, true);
+       if (r)
+               goto error_free;
+
+       list_for_each_entry(entry, &list, head) {
+               domain = radeon_mem_type_to_domain(entry->bo->mem.mem_type);
+               /* if anything is swapped out don't swap it in here,
+                  just abort and wait for the next CS */
+               if (domain == RADEON_GEM_DOMAIN_CPU)
+                       goto error_unreserve;
+       }
+
+       mutex_lock(&bo_va->vm->mutex);
+       r = radeon_vm_clear_freed(rdev, bo_va->vm);
+       if (r)
+               goto error_unlock;
+
+       if (bo_va->it.start)
+               r = radeon_vm_bo_update(rdev, bo_va, &bo_va->bo->tbo.mem);
+
+error_unlock:
+       mutex_unlock(&bo_va->vm->mutex);
+
+error_unreserve:
+       ttm_eu_backoff_reservation(&ticket, &list);
+
+error_free:
+       drm_free_large(vm_bos);
+
+       if (r)
+               DRM_ERROR("Couldn't update BO_VA (%d)\n", r);
+}
+
 int radeon_gem_va_ioctl(struct drm_device *dev, void *data,
                          struct drm_file *filp)
 {
@@ -601,6 +680,7 @@ int radeon_gem_va_ioctl(struct drm_device *dev, void *data,
                if (bo_va->it.start) {
                        args->operation = RADEON_VA_RESULT_VA_EXIST;
                        args->offset = bo_va->it.start * RADEON_GPU_PAGE_SIZE;
+                       radeon_bo_unreserve(rbo);
                        goto out;
                }
                r = radeon_vm_bo_set_addr(rdev, bo_va, args->offset, args->flags);
@@ -611,12 +691,13 @@ int radeon_gem_va_ioctl(struct drm_device *dev, void *data,
        default:
                break;
        }
+       if (!r)
+               radeon_gem_va_update_vm(rdev, bo_va);
        args->operation = RADEON_VA_RESULT_OK;
        if (r) {
                args->operation = RADEON_VA_RESULT_ERROR;
        }
 out:
-       radeon_bo_unreserve(rbo);
        drm_gem_object_unreference_unlocked(gobj);
        return r;
 }
@@ -682,6 +763,7 @@ int radeon_mode_dumb_create(struct drm_file *file_priv,
                return -ENOMEM;
 
        r = drm_gem_handle_create(file_priv, gobj, &handle);
+       gobj->dumb = true;
        /* drop reference from allocate - handle holds it now */
        drm_gem_object_unreference_unlocked(gobj);
        if (r) {
index 3f39fcca4d0744ec666630be4e3672ada57cba08..c39ce1f057037e6ae3ddae1c11be1d07d1572b95 100644 (file)
@@ -64,10 +64,7 @@ int radeon_ib_get(struct radeon_device *rdev, int ring,
                return r;
        }
 
-       r = radeon_semaphore_create(rdev, &ib->semaphore);
-       if (r) {
-               return r;
-       }
+       radeon_sync_create(&ib->sync);
 
        ib->ring = ring;
        ib->fence = NULL;
@@ -96,7 +93,7 @@ int radeon_ib_get(struct radeon_device *rdev, int ring,
  */
 void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib)
 {
-       radeon_semaphore_free(rdev, &ib->semaphore, ib->fence);
+       radeon_sync_free(rdev, &ib->sync, ib->fence);
        radeon_sa_bo_free(rdev, &ib->sa_bo, ib->fence);
        radeon_fence_unref(&ib->fence);
 }
@@ -145,11 +142,11 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,
        if (ib->vm) {
                struct radeon_fence *vm_id_fence;
                vm_id_fence = radeon_vm_grab_id(rdev, ib->vm, ib->ring);
-               radeon_semaphore_sync_fence(ib->semaphore, vm_id_fence);
+               radeon_sync_fence(&ib->sync, vm_id_fence);
        }
 
        /* sync with other rings */
-       r = radeon_semaphore_sync_rings(rdev, ib->semaphore, ib->ring);
+       r = radeon_sync_rings(rdev, &ib->sync, ib->ring);
        if (r) {
                dev_err(rdev->dev, "failed to sync rings (%d)\n", r);
                radeon_ring_unlock_undo(rdev, ring);
@@ -157,11 +154,12 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,
        }
 
        if (ib->vm)
-               radeon_vm_flush(rdev, ib->vm, ib->ring);
+               radeon_vm_flush(rdev, ib->vm, ib->ring,
+                               ib->sync.last_vm_update);
 
        if (const_ib) {
                radeon_ring_ib_execute(rdev, const_ib->ring, const_ib);
-               radeon_semaphore_free(rdev, &const_ib->semaphore, NULL);
+               radeon_sync_free(rdev, &const_ib->sync, NULL);
        }
        radeon_ring_ib_execute(rdev, ib->ring, ib);
        r = radeon_fence_emit(rdev, &ib->fence, ib->ring);
index 7784911d78ef6fc54d6aeea23950f4585d3c74c4..00fc59762e0df3bba0758d1f18e90328e5726635 100644 (file)
@@ -185,6 +185,16 @@ static bool radeon_msi_ok(struct radeon_device *rdev)
        if (rdev->flags & RADEON_IS_AGP)
                return false;
 
+       /*
+        * Older chips have a HW limitation, they can only generate 40 bits
+        * of address for "64-bit" MSIs which breaks on some platforms, notably
+        * IBM POWER servers, so we limit them
+        */
+       if (rdev->family < CHIP_BONAIRE) {
+               dev_info(rdev->dev, "radeon: MSI limited to 32-bit\n");
+               rdev->pdev->no_64bit_msi = 1;
+       }
+
        /* force MSI on */
        if (radeon_msi == 1)
                return true;
diff --git a/drivers/gpu/drm/radeon/radeon_kfd.c b/drivers/gpu/drm/radeon/radeon_kfd.c
new file mode 100644 (file)
index 0000000..065d020
--- /dev/null
@@ -0,0 +1,563 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/fdtable.h>
+#include <linux/uaccess.h>
+#include <drm/drmP.h>
+#include "radeon.h"
+#include "cikd.h"
+#include "cik_reg.h"
+#include "radeon_kfd.h"
+
+#define CIK_PIPE_PER_MEC       (4)
+
+struct kgd_mem {
+       struct radeon_sa_bo *sa_bo;
+       uint64_t gpu_addr;
+       void *ptr;
+};
+
+static int init_sa_manager(struct kgd_dev *kgd, unsigned int size);
+static void fini_sa_manager(struct kgd_dev *kgd);
+
+static int allocate_mem(struct kgd_dev *kgd, size_t size, size_t alignment,
+               enum kgd_memory_pool pool, struct kgd_mem **mem);
+
+static void free_mem(struct kgd_dev *kgd, struct kgd_mem *mem);
+
+static uint64_t get_vmem_size(struct kgd_dev *kgd);
+static uint64_t get_gpu_clock_counter(struct kgd_dev *kgd);
+
+static uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd);
+
+/*
+ * Register access functions
+ */
+
+static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid,
+               uint32_t sh_mem_config, uint32_t sh_mem_ape1_base,
+               uint32_t sh_mem_ape1_limit, uint32_t sh_mem_bases);
+
+static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
+                                       unsigned int vmid);
+
+static int kgd_init_memory(struct kgd_dev *kgd);
+
+static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id,
+                               uint32_t hpd_size, uint64_t hpd_gpu_addr);
+
+static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
+                       uint32_t queue_id, uint32_t __user *wptr);
+
+static bool kgd_hqd_is_occupies(struct kgd_dev *kgd, uint64_t queue_address,
+                               uint32_t pipe_id, uint32_t queue_id);
+
+static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
+                               unsigned int timeout, uint32_t pipe_id,
+                               uint32_t queue_id);
+
+static const struct kfd2kgd_calls kfd2kgd = {
+       .init_sa_manager = init_sa_manager,
+       .fini_sa_manager = fini_sa_manager,
+       .allocate_mem = allocate_mem,
+       .free_mem = free_mem,
+       .get_vmem_size = get_vmem_size,
+       .get_gpu_clock_counter = get_gpu_clock_counter,
+       .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz,
+       .program_sh_mem_settings = kgd_program_sh_mem_settings,
+       .set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
+       .init_memory = kgd_init_memory,
+       .init_pipeline = kgd_init_pipeline,
+       .hqd_load = kgd_hqd_load,
+       .hqd_is_occupies = kgd_hqd_is_occupies,
+       .hqd_destroy = kgd_hqd_destroy,
+};
+
+static const struct kgd2kfd_calls *kgd2kfd;
+
+bool radeon_kfd_init(void)
+{
+       bool (*kgd2kfd_init_p)(unsigned, const struct kfd2kgd_calls*,
+                               const struct kgd2kfd_calls**);
+
+       kgd2kfd_init_p = symbol_request(kgd2kfd_init);
+
+       if (kgd2kfd_init_p == NULL)
+               return false;
+
+       if (!kgd2kfd_init_p(KFD_INTERFACE_VERSION, &kfd2kgd, &kgd2kfd)) {
+               symbol_put(kgd2kfd_init);
+               kgd2kfd = NULL;
+
+               return false;
+       }
+
+       return true;
+}
+
+void radeon_kfd_fini(void)
+{
+       if (kgd2kfd) {
+               kgd2kfd->exit();
+               symbol_put(kgd2kfd_init);
+       }
+}
+
+void radeon_kfd_device_probe(struct radeon_device *rdev)
+{
+       if (kgd2kfd)
+               rdev->kfd = kgd2kfd->probe((struct kgd_dev *)rdev, rdev->pdev);
+}
+
+void radeon_kfd_device_init(struct radeon_device *rdev)
+{
+       if (rdev->kfd) {
+               struct kgd2kfd_shared_resources gpu_resources = {
+                       .compute_vmid_bitmap = 0xFF00,
+
+                       .first_compute_pipe = 1,
+                       .compute_pipe_count = 8 - 1,
+               };
+
+               radeon_doorbell_get_kfd_info(rdev,
+                               &gpu_resources.doorbell_physical_address,
+                               &gpu_resources.doorbell_aperture_size,
+                               &gpu_resources.doorbell_start_offset);
+
+               kgd2kfd->device_init(rdev->kfd, &gpu_resources);
+       }
+}
+
+void radeon_kfd_device_fini(struct radeon_device *rdev)
+{
+       if (rdev->kfd) {
+               kgd2kfd->device_exit(rdev->kfd);
+               rdev->kfd = NULL;
+       }
+}
+
+void radeon_kfd_interrupt(struct radeon_device *rdev, const void *ih_ring_entry)
+{
+       if (rdev->kfd)
+               kgd2kfd->interrupt(rdev->kfd, ih_ring_entry);
+}
+
+void radeon_kfd_suspend(struct radeon_device *rdev)
+{
+       if (rdev->kfd)
+               kgd2kfd->suspend(rdev->kfd);
+}
+
+int radeon_kfd_resume(struct radeon_device *rdev)
+{
+       int r = 0;
+
+       if (rdev->kfd)
+               r = kgd2kfd->resume(rdev->kfd);
+
+       return r;
+}
+
+static u32 pool_to_domain(enum kgd_memory_pool p)
+{
+       switch (p) {
+       case KGD_POOL_FRAMEBUFFER: return RADEON_GEM_DOMAIN_VRAM;
+       default: return RADEON_GEM_DOMAIN_GTT;
+       }
+}
+
+static int init_sa_manager(struct kgd_dev *kgd, unsigned int size)
+{
+       struct radeon_device *rdev = (struct radeon_device *)kgd;
+       int r;
+
+       BUG_ON(kgd == NULL);
+
+       r = radeon_sa_bo_manager_init(rdev, &rdev->kfd_bo,
+                                     size,
+                                     RADEON_GPU_PAGE_SIZE,
+                                     RADEON_GEM_DOMAIN_GTT,
+                                     RADEON_GEM_GTT_WC);
+
+       if (r)
+               return r;
+
+       r = radeon_sa_bo_manager_start(rdev, &rdev->kfd_bo);
+       if (r)
+               radeon_sa_bo_manager_fini(rdev, &rdev->kfd_bo);
+
+       return r;
+}
+
+static void fini_sa_manager(struct kgd_dev *kgd)
+{
+       struct radeon_device *rdev = (struct radeon_device *)kgd;
+
+       BUG_ON(kgd == NULL);
+
+       radeon_sa_bo_manager_suspend(rdev, &rdev->kfd_bo);
+       radeon_sa_bo_manager_fini(rdev, &rdev->kfd_bo);
+}
+
+static int allocate_mem(struct kgd_dev *kgd, size_t size, size_t alignment,
+               enum kgd_memory_pool pool, struct kgd_mem **mem)
+{
+       struct radeon_device *rdev = (struct radeon_device *)kgd;
+       u32 domain;
+       int r;
+
+       BUG_ON(kgd == NULL);
+
+       domain = pool_to_domain(pool);
+       if (domain != RADEON_GEM_DOMAIN_GTT) {
+               dev_err(rdev->dev,
+                       "Only allowed to allocate gart memory for kfd\n");
+               return -EINVAL;
+       }
+
+       *mem = kmalloc(sizeof(struct kgd_mem), GFP_KERNEL);
+       if ((*mem) == NULL)
+               return -ENOMEM;
+
+       r = radeon_sa_bo_new(rdev, &rdev->kfd_bo, &(*mem)->sa_bo, size,
+                               alignment);
+       if (r) {
+               dev_err(rdev->dev, "failed to get memory for kfd (%d)\n", r);
+               return r;
+       }
+
+       (*mem)->ptr = radeon_sa_bo_cpu_addr((*mem)->sa_bo);
+       (*mem)->gpu_addr = radeon_sa_bo_gpu_addr((*mem)->sa_bo);
+
+       return 0;
+}
+
+static void free_mem(struct kgd_dev *kgd, struct kgd_mem *mem)
+{
+       struct radeon_device *rdev = (struct radeon_device *)kgd;
+
+       BUG_ON(kgd == NULL);
+
+       radeon_sa_bo_free(rdev, &mem->sa_bo, NULL);
+       kfree(mem);
+}
+
+static uint64_t get_vmem_size(struct kgd_dev *kgd)
+{
+       struct radeon_device *rdev = (struct radeon_device *)kgd;
+
+       BUG_ON(kgd == NULL);
+
+       return rdev->mc.real_vram_size;
+}
+
+static uint64_t get_gpu_clock_counter(struct kgd_dev *kgd)
+{
+       struct radeon_device *rdev = (struct radeon_device *)kgd;
+
+       return rdev->asic->get_gpu_clock_counter(rdev);
+}
+
+static uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd)
+{
+       struct radeon_device *rdev = (struct radeon_device *)kgd;
+
+       /* The sclk is in quantas of 10kHz */
+       return rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk / 100;
+}
+
+static inline struct radeon_device *get_radeon_device(struct kgd_dev *kgd)
+{
+       return (struct radeon_device *)kgd;
+}
+
+static void write_register(struct kgd_dev *kgd, uint32_t offset, uint32_t value)
+{
+       struct radeon_device *rdev = get_radeon_device(kgd);
+
+       writel(value, (void __iomem *)(rdev->rmmio + offset));
+}
+
+static uint32_t read_register(struct kgd_dev *kgd, uint32_t offset)
+{
+       struct radeon_device *rdev = get_radeon_device(kgd);
+
+       return readl((void __iomem *)(rdev->rmmio + offset));
+}
+
+static void lock_srbm(struct kgd_dev *kgd, uint32_t mec, uint32_t pipe,
+                       uint32_t queue, uint32_t vmid)
+{
+       struct radeon_device *rdev = get_radeon_device(kgd);
+       uint32_t value = PIPEID(pipe) | MEID(mec) | VMID(vmid) | QUEUEID(queue);
+
+       mutex_lock(&rdev->srbm_mutex);
+       write_register(kgd, SRBM_GFX_CNTL, value);
+}
+
+static void unlock_srbm(struct kgd_dev *kgd)
+{
+       struct radeon_device *rdev = get_radeon_device(kgd);
+
+       write_register(kgd, SRBM_GFX_CNTL, 0);
+       mutex_unlock(&rdev->srbm_mutex);
+}
+
+static void acquire_queue(struct kgd_dev *kgd, uint32_t pipe_id,
+                               uint32_t queue_id)
+{
+       uint32_t mec = (++pipe_id / CIK_PIPE_PER_MEC) + 1;
+       uint32_t pipe = (pipe_id % CIK_PIPE_PER_MEC);
+
+       lock_srbm(kgd, mec, pipe, queue_id, 0);
+}
+
+static void release_queue(struct kgd_dev *kgd)
+{
+       unlock_srbm(kgd);
+}
+
+static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid,
+                                       uint32_t sh_mem_config,
+                                       uint32_t sh_mem_ape1_base,
+                                       uint32_t sh_mem_ape1_limit,
+                                       uint32_t sh_mem_bases)
+{
+       lock_srbm(kgd, 0, 0, 0, vmid);
+
+       write_register(kgd, SH_MEM_CONFIG, sh_mem_config);
+       write_register(kgd, SH_MEM_APE1_BASE, sh_mem_ape1_base);
+       write_register(kgd, SH_MEM_APE1_LIMIT, sh_mem_ape1_limit);
+       write_register(kgd, SH_MEM_BASES, sh_mem_bases);
+
+       unlock_srbm(kgd);
+}
+
+static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
+                                       unsigned int vmid)
+{
+       /*
+        * We have to assume that there is no outstanding mapping.
+        * The ATC_VMID_PASID_MAPPING_UPDATE_STATUS bit could be 0
+        * because a mapping is in progress or because a mapping finished and
+        * the SW cleared it.
+        * So the protocol is to always wait & clear.
+        */
+       uint32_t pasid_mapping = (pasid == 0) ? 0 :
+                               (uint32_t)pasid | ATC_VMID_PASID_MAPPING_VALID;
+
+       write_register(kgd, ATC_VMID0_PASID_MAPPING + vmid*sizeof(uint32_t),
+                       pasid_mapping);
+
+       while (!(read_register(kgd, ATC_VMID_PASID_MAPPING_UPDATE_STATUS) &
+                                                               (1U << vmid)))
+               cpu_relax();
+       write_register(kgd, ATC_VMID_PASID_MAPPING_UPDATE_STATUS, 1U << vmid);
+
+       return 0;
+}
+
+static int kgd_init_memory(struct kgd_dev *kgd)
+{
+       /*
+        * Configure apertures:
+        * LDS:         0x60000000'00000000 - 0x60000001'00000000 (4GB)
+        * Scratch:     0x60000001'00000000 - 0x60000002'00000000 (4GB)
+        * GPUVM:       0x60010000'00000000 - 0x60020000'00000000 (1TB)
+        */
+       int i;
+       uint32_t sh_mem_bases = PRIVATE_BASE(0x6000) | SHARED_BASE(0x6000);
+
+       for (i = 8; i < 16; i++) {
+               uint32_t sh_mem_config;
+
+               lock_srbm(kgd, 0, 0, 0, i);
+
+               sh_mem_config = ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED);
+               sh_mem_config |= DEFAULT_MTYPE(MTYPE_NONCACHED);
+
+               write_register(kgd, SH_MEM_CONFIG, sh_mem_config);
+
+               write_register(kgd, SH_MEM_BASES, sh_mem_bases);
+
+               /* Scratch aperture is not supported for now. */
+               write_register(kgd, SH_STATIC_MEM_CONFIG, 0);
+
+               /* APE1 disabled for now. */
+               write_register(kgd, SH_MEM_APE1_BASE, 1);
+               write_register(kgd, SH_MEM_APE1_LIMIT, 0);
+
+               unlock_srbm(kgd);
+       }
+
+       return 0;
+}
+
+static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id,
+                               uint32_t hpd_size, uint64_t hpd_gpu_addr)
+{
+       uint32_t mec = (++pipe_id / CIK_PIPE_PER_MEC) + 1;
+       uint32_t pipe = (pipe_id % CIK_PIPE_PER_MEC);
+
+       lock_srbm(kgd, mec, pipe, 0, 0);
+       write_register(kgd, CP_HPD_EOP_BASE_ADDR,
+                       lower_32_bits(hpd_gpu_addr >> 8));
+       write_register(kgd, CP_HPD_EOP_BASE_ADDR_HI,
+                       upper_32_bits(hpd_gpu_addr >> 8));
+       write_register(kgd, CP_HPD_EOP_VMID, 0);
+       write_register(kgd, CP_HPD_EOP_CONTROL, hpd_size);
+       unlock_srbm(kgd);
+
+       return 0;
+}
+
+static inline struct cik_mqd *get_mqd(void *mqd)
+{
+       return (struct cik_mqd *)mqd;
+}
+
+static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
+                       uint32_t queue_id, uint32_t __user *wptr)
+{
+       uint32_t wptr_shadow, is_wptr_shadow_valid;
+       struct cik_mqd *m;
+
+       m = get_mqd(mqd);
+
+       is_wptr_shadow_valid = !get_user(wptr_shadow, wptr);
+
+       acquire_queue(kgd, pipe_id, queue_id);
+       write_register(kgd, CP_MQD_BASE_ADDR, m->cp_mqd_base_addr_lo);
+       write_register(kgd, CP_MQD_BASE_ADDR_HI, m->cp_mqd_base_addr_hi);
+       write_register(kgd, CP_MQD_CONTROL, m->cp_mqd_control);
+
+       write_register(kgd, CP_HQD_PQ_BASE, m->cp_hqd_pq_base_lo);
+       write_register(kgd, CP_HQD_PQ_BASE_HI, m->cp_hqd_pq_base_hi);
+       write_register(kgd, CP_HQD_PQ_CONTROL, m->cp_hqd_pq_control);
+
+       write_register(kgd, CP_HQD_IB_CONTROL, m->cp_hqd_ib_control);
+       write_register(kgd, CP_HQD_IB_BASE_ADDR, m->cp_hqd_ib_base_addr_lo);
+       write_register(kgd, CP_HQD_IB_BASE_ADDR_HI, m->cp_hqd_ib_base_addr_hi);
+
+       write_register(kgd, CP_HQD_IB_RPTR, m->cp_hqd_ib_rptr);
+
+       write_register(kgd, CP_HQD_PERSISTENT_STATE,
+                       m->cp_hqd_persistent_state);
+       write_register(kgd, CP_HQD_SEMA_CMD, m->cp_hqd_sema_cmd);
+       write_register(kgd, CP_HQD_MSG_TYPE, m->cp_hqd_msg_type);
+
+       write_register(kgd, CP_HQD_ATOMIC0_PREOP_LO,
+                       m->cp_hqd_atomic0_preop_lo);
+
+       write_register(kgd, CP_HQD_ATOMIC0_PREOP_HI,
+                       m->cp_hqd_atomic0_preop_hi);
+
+       write_register(kgd, CP_HQD_ATOMIC1_PREOP_LO,
+                       m->cp_hqd_atomic1_preop_lo);
+
+       write_register(kgd, CP_HQD_ATOMIC1_PREOP_HI,
+                       m->cp_hqd_atomic1_preop_hi);
+
+       write_register(kgd, CP_HQD_PQ_RPTR_REPORT_ADDR,
+                       m->cp_hqd_pq_rptr_report_addr_lo);
+
+       write_register(kgd, CP_HQD_PQ_RPTR_REPORT_ADDR_HI,
+                       m->cp_hqd_pq_rptr_report_addr_hi);
+
+       write_register(kgd, CP_HQD_PQ_RPTR, m->cp_hqd_pq_rptr);
+
+       write_register(kgd, CP_HQD_PQ_WPTR_POLL_ADDR,
+                       m->cp_hqd_pq_wptr_poll_addr_lo);
+
+       write_register(kgd, CP_HQD_PQ_WPTR_POLL_ADDR_HI,
+                       m->cp_hqd_pq_wptr_poll_addr_hi);
+
+       write_register(kgd, CP_HQD_PQ_DOORBELL_CONTROL,
+                       m->cp_hqd_pq_doorbell_control);
+
+       write_register(kgd, CP_HQD_VMID, m->cp_hqd_vmid);
+
+       write_register(kgd, CP_HQD_QUANTUM, m->cp_hqd_quantum);
+
+       write_register(kgd, CP_HQD_PIPE_PRIORITY, m->cp_hqd_pipe_priority);
+       write_register(kgd, CP_HQD_QUEUE_PRIORITY, m->cp_hqd_queue_priority);
+
+       write_register(kgd, CP_HQD_IQ_RPTR, m->cp_hqd_iq_rptr);
+
+       if (is_wptr_shadow_valid)
+               write_register(kgd, CP_HQD_PQ_WPTR, wptr_shadow);
+
+       write_register(kgd, CP_HQD_ACTIVE, m->cp_hqd_active);
+       release_queue(kgd);
+
+       return 0;
+}
+
+static bool kgd_hqd_is_occupies(struct kgd_dev *kgd, uint64_t queue_address,
+                               uint32_t pipe_id, uint32_t queue_id)
+{
+       uint32_t act;
+       bool retval = false;
+       uint32_t low, high;
+
+       acquire_queue(kgd, pipe_id, queue_id);
+       act = read_register(kgd, CP_HQD_ACTIVE);
+       if (act) {
+               low = lower_32_bits(queue_address >> 8);
+               high = upper_32_bits(queue_address >> 8);
+
+               if (low == read_register(kgd, CP_HQD_PQ_BASE) &&
+                               high == read_register(kgd, CP_HQD_PQ_BASE_HI))
+                       retval = true;
+       }
+       release_queue(kgd);
+       return retval;
+}
+
+static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
+                               unsigned int timeout, uint32_t pipe_id,
+                               uint32_t queue_id)
+{
+       uint32_t temp;
+
+       acquire_queue(kgd, pipe_id, queue_id);
+       write_register(kgd, CP_HQD_PQ_DOORBELL_CONTROL, 0);
+
+       write_register(kgd, CP_HQD_DEQUEUE_REQUEST, reset_type);
+
+       while (true) {
+               temp = read_register(kgd, CP_HQD_ACTIVE);
+               if (temp & 0x1)
+                       break;
+               if (timeout == 0) {
+                       pr_err("kfd: cp queue preemption time out (%dms)\n",
+                               temp);
+                       return -ETIME;
+               }
+               msleep(20);
+               timeout -= 20;
+       }
+
+       release_queue(kgd);
+       return 0;
+}
diff --git a/drivers/gpu/drm/radeon/radeon_kfd.h b/drivers/gpu/drm/radeon/radeon_kfd.h
new file mode 100644 (file)
index 0000000..f90e161
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * radeon_kfd.h defines the private interface between the
+ * AMD kernel graphics drivers and the AMD KFD.
+ */
+
+#ifndef RADEON_KFD_H_INCLUDED
+#define RADEON_KFD_H_INCLUDED
+
+#include <linux/types.h>
+#include "../amd/include/kgd_kfd_interface.h"
+
+struct radeon_device;
+
+bool radeon_kfd_init(void);
+void radeon_kfd_fini(void);
+
+void radeon_kfd_suspend(struct radeon_device *rdev);
+int radeon_kfd_resume(struct radeon_device *rdev);
+void radeon_kfd_interrupt(struct radeon_device *rdev,
+                       const void *ih_ring_entry);
+void radeon_kfd_device_probe(struct radeon_device *rdev);
+void radeon_kfd_device_init(struct radeon_device *rdev);
+void radeon_kfd_device_fini(struct radeon_device *rdev);
+
+#endif /* RADEON_KFD_H_INCLUDED */
index 8309b11e674d8506bfeb3f05530407ede4b60642..f4dd26ae33e569073bfaaeb86be8495f20aa4a7c 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
 
+#include "radeon_kfd.h"
+
 #if defined(CONFIG_VGA_SWITCHEROO)
 bool radeon_has_atpx(void);
 #else
@@ -63,6 +65,8 @@ int radeon_driver_unload_kms(struct drm_device *dev)
 
        pm_runtime_get_sync(dev->dev);
 
+       radeon_kfd_device_fini(rdev);
+
        radeon_acpi_fini(rdev);
        
        radeon_modeset_fini(rdev);
@@ -142,6 +146,9 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)
                                "Error during ACPI methods call\n");
        }
 
+       radeon_kfd_device_probe(rdev);
+       radeon_kfd_device_init(rdev);
+
        if (radeon_is_px(dev)) {
                pm_runtime_use_autosuspend(dev->dev);
                pm_runtime_set_autosuspend_delay(dev->dev, 5000);
@@ -621,8 +628,6 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
                                                  RADEON_VA_IB_OFFSET,
                                                  RADEON_VM_PAGE_READABLE |
                                                  RADEON_VM_PAGE_SNOOPED);
-
-                       radeon_bo_unreserve(rdev->ring_tmp_bo.bo);
                        if (r) {
                                radeon_vm_fini(rdev, vm);
                                kfree(fpriv);
index 04db2fdd869271f81482e75913d6ec4002ffecac..f3d87cdd5c9dcafbae4850919ea5a9bd50dc7a00 100644 (file)
@@ -321,6 +321,10 @@ struct radeon_crtc {
        uint32_t crtc_offset;
        struct drm_gem_object *cursor_bo;
        uint64_t cursor_addr;
+       int cursor_x;
+       int cursor_y;
+       int cursor_hot_x;
+       int cursor_hot_y;
        int cursor_width;
        int cursor_height;
        int max_cursor_width;
@@ -462,6 +466,7 @@ struct radeon_gpio_rec {
        u8 id;
        u32 reg;
        u32 mask;
+       u32 shift;
 };
 
 struct radeon_hpd {
@@ -748,6 +753,8 @@ extern bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
 extern bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
                                             struct radeon_atom_ss *ss,
                                             int id, u32 clock);
+extern struct radeon_gpio_rec radeon_atombios_lookup_gpio(struct radeon_device *rdev,
+                                                         u8 id);
 
 extern void radeon_compute_pll_legacy(struct radeon_pll *pll,
                                      uint64_t freq,
@@ -802,11 +809,13 @@ extern int radeon_crtc_set_base_atomic(struct drm_crtc *crtc,
 extern int radeon_crtc_do_set_base(struct drm_crtc *crtc,
                                   struct drm_framebuffer *fb,
                                   int x, int y, int atomic);
-extern int radeon_crtc_cursor_set(struct drm_crtc *crtc,
-                                 struct drm_file *file_priv,
-                                 uint32_t handle,
-                                 uint32_t width,
-                                 uint32_t height);
+extern int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
+                                  struct drm_file *file_priv,
+                                  uint32_t handle,
+                                  uint32_t width,
+                                  uint32_t height,
+                                  int32_t hot_x,
+                                  int32_t hot_y);
 extern int radeon_crtc_cursor_move(struct drm_crtc *crtc,
                                   int x, int y);
 
index 99a960a4f30265c893a411763843a260d38e6a41..87b00d902bf756d362ec12249105b44e1ae64ac9 100644 (file)
@@ -99,22 +99,39 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
 
        rbo->placement.placement = rbo->placements;
        rbo->placement.busy_placement = rbo->placements;
-       if (domain & RADEON_GEM_DOMAIN_VRAM)
+       if (domain & RADEON_GEM_DOMAIN_VRAM) {
+               /* Try placing BOs which don't need CPU access outside of the
+                * CPU accessible part of VRAM
+                */
+               if ((rbo->flags & RADEON_GEM_NO_CPU_ACCESS) &&
+                   rbo->rdev->mc.visible_vram_size < rbo->rdev->mc.real_vram_size) {
+                       rbo->placements[c].fpfn =
+                               rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
+                       rbo->placements[c++].flags = TTM_PL_FLAG_WC |
+                                                    TTM_PL_FLAG_UNCACHED |
+                                                    TTM_PL_FLAG_VRAM;
+               }
+
+               rbo->placements[c].fpfn = 0;
                rbo->placements[c++].flags = TTM_PL_FLAG_WC |
                                             TTM_PL_FLAG_UNCACHED |
                                             TTM_PL_FLAG_VRAM;
+       }
 
        if (domain & RADEON_GEM_DOMAIN_GTT) {
                if (rbo->flags & RADEON_GEM_GTT_UC) {
+                       rbo->placements[c].fpfn = 0;
                        rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED |
                                TTM_PL_FLAG_TT;
 
                } else if ((rbo->flags & RADEON_GEM_GTT_WC) ||
                           (rbo->rdev->flags & RADEON_IS_AGP)) {
+                       rbo->placements[c].fpfn = 0;
                        rbo->placements[c++].flags = TTM_PL_FLAG_WC |
                                TTM_PL_FLAG_UNCACHED |
                                TTM_PL_FLAG_TT;
                } else {
+                       rbo->placements[c].fpfn = 0;
                        rbo->placements[c++].flags = TTM_PL_FLAG_CACHED |
                                                     TTM_PL_FLAG_TT;
                }
@@ -122,30 +139,35 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
 
        if (domain & RADEON_GEM_DOMAIN_CPU) {
                if (rbo->flags & RADEON_GEM_GTT_UC) {
+                       rbo->placements[c].fpfn = 0;
                        rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED |
                                TTM_PL_FLAG_SYSTEM;
 
                } else if ((rbo->flags & RADEON_GEM_GTT_WC) ||
                    rbo->rdev->flags & RADEON_IS_AGP) {
+                       rbo->placements[c].fpfn = 0;
                        rbo->placements[c++].flags = TTM_PL_FLAG_WC |
                                TTM_PL_FLAG_UNCACHED |
                                TTM_PL_FLAG_SYSTEM;
                } else {
+                       rbo->placements[c].fpfn = 0;
                        rbo->placements[c++].flags = TTM_PL_FLAG_CACHED |
                                                     TTM_PL_FLAG_SYSTEM;
                }
        }
-       if (!c)
+       if (!c) {
+               rbo->placements[c].fpfn = 0;
                rbo->placements[c++].flags = TTM_PL_MASK_CACHING |
                                             TTM_PL_FLAG_SYSTEM;
+       }
 
        rbo->placement.num_placement = c;
        rbo->placement.num_busy_placement = c;
 
        for (i = 0; i < c; ++i) {
-               rbo->placements[i].fpfn = 0;
                if ((rbo->flags & RADEON_GEM_CPU_ACCESS) &&
-                   (rbo->placements[i].flags & TTM_PL_FLAG_VRAM))
+                   (rbo->placements[i].flags & TTM_PL_FLAG_VRAM) &&
+                   !rbo->placements[i].fpfn)
                        rbo->placements[i].lpfn =
                                rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
                else
@@ -157,9 +179,7 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
         * improve fragmentation quality.
         * 512kb was measured as the most optimal number.
         */
-       if (!((rbo->flags & RADEON_GEM_CPU_ACCESS) &&
-             (rbo->placements[i].flags & TTM_PL_FLAG_VRAM)) &&
-           rbo->tbo.mem.size > 512 * 1024) {
+       if (rbo->tbo.mem.size > 512 * 1024) {
                for (i = 0; i < c; i++) {
                        rbo->placements[i].flags |= TTM_PL_FLAG_TOPDOWN;
                }
@@ -501,6 +521,9 @@ int radeon_bo_list_validate(struct radeon_device *rdev,
                        u32 current_domain =
                                radeon_mem_type_to_domain(bo->tbo.mem.mem_type);
 
+                       WARN_ONCE(bo->gem_base.dumb,
+                                 "GPU use of dumb buffer is illegal.\n");
+
                        /* Check if this buffer will be moved and don't move it
                         * if we have moved too many buffers for this IB already.
                         *
@@ -743,8 +766,8 @@ int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
 {
        struct radeon_device *rdev;
        struct radeon_bo *rbo;
-       unsigned long offset, size;
-       int r;
+       unsigned long offset, size, lpfn;
+       int i, r;
 
        if (!radeon_ttm_bo_is_radeon_bo(bo))
                return 0;
@@ -761,7 +784,13 @@ int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
 
        /* hurrah the memory is not visible ! */
        radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM);
-       rbo->placements[0].lpfn = rdev->mc.visible_vram_size >> PAGE_SHIFT;
+       lpfn =  rdev->mc.visible_vram_size >> PAGE_SHIFT;
+       for (i = 0; i < rbo->placement.num_placement; i++) {
+               /* Force into visible VRAM */
+               if ((rbo->placements[i].flags & TTM_PL_FLAG_VRAM) &&
+                   (!rbo->placements[i].lpfn || rbo->placements[i].lpfn > lpfn))
+                       rbo->placements[i].lpfn = lpfn;
+       }
        r = ttm_bo_validate(bo, &rbo->placement, false, false);
        if (unlikely(r == -ENOMEM)) {
                radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT);
@@ -792,3 +821,22 @@ int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, bool no_wait)
        ttm_bo_unreserve(&bo->tbo);
        return r;
 }
+
+/**
+ * radeon_bo_fence - add fence to buffer object
+ *
+ * @bo: buffer object in question
+ * @fence: fence to add
+ * @shared: true if fence should be added shared
+ *
+ */
+void radeon_bo_fence(struct radeon_bo *bo, struct radeon_fence *fence,
+                     bool shared)
+{
+       struct reservation_object *resv = bo->tbo.resv;
+
+       if (shared)
+               reservation_object_add_shared_fence(resv, &fence->base);
+       else
+               reservation_object_add_excl_fence(resv, &fence->base);
+}
index 1b8ec7917154809e10336fb346c6aacbafa72939..3b0b377f76cb08c2aa6124896818c6567ff52db4 100644 (file)
@@ -155,6 +155,8 @@ extern void radeon_bo_move_notify(struct ttm_buffer_object *bo,
                                  struct ttm_mem_reg *new_mem);
 extern int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo);
 extern int radeon_bo_get_surface_reg(struct radeon_bo *bo);
+extern void radeon_bo_fence(struct radeon_bo *bo, struct radeon_fence *fence,
+                           bool shared);
 
 /*
  * sub allocation
index 6deb08f045b758a9cbaefec886177b86c950a567..e6ad54cdfa6279284771d4df897f7860b0ae06c6 100644 (file)
 int radeon_semaphore_create(struct radeon_device *rdev,
                            struct radeon_semaphore **semaphore)
 {
-       uint64_t *cpu_addr;
-       int i, r;
+       int r;
 
        *semaphore = kmalloc(sizeof(struct radeon_semaphore), GFP_KERNEL);
        if (*semaphore == NULL) {
                return -ENOMEM;
        }
-       r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &(*semaphore)->sa_bo,
-                            8 * RADEON_NUM_SYNCS, 8);
+       r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo,
+                            &(*semaphore)->sa_bo, 8, 8);
        if (r) {
                kfree(*semaphore);
                *semaphore = NULL;
@@ -51,12 +50,7 @@ int radeon_semaphore_create(struct radeon_device *rdev,
        (*semaphore)->waiters = 0;
        (*semaphore)->gpu_addr = radeon_sa_bo_gpu_addr((*semaphore)->sa_bo);
 
-       cpu_addr = radeon_sa_bo_cpu_addr((*semaphore)->sa_bo);
-       for (i = 0; i < RADEON_NUM_SYNCS; ++i)
-               cpu_addr[i] = 0;
-
-       for (i = 0; i < RADEON_NUM_RINGS; ++i)
-               (*semaphore)->sync_to[i] = NULL;
+       *((uint64_t *)radeon_sa_bo_cpu_addr((*semaphore)->sa_bo)) = 0;
 
        return 0;
 }
@@ -95,146 +89,6 @@ bool radeon_semaphore_emit_wait(struct radeon_device *rdev, int ridx,
        return false;
 }
 
-/**
- * radeon_semaphore_sync_fence - use the semaphore to sync to a fence
- *
- * @semaphore: semaphore object to add fence to
- * @fence: fence to sync to
- *
- * Sync to the fence using this semaphore object
- */
-void radeon_semaphore_sync_fence(struct radeon_semaphore *semaphore,
-                                struct radeon_fence *fence)
-{
-        struct radeon_fence *other;
-
-        if (!fence)
-                return;
-
-        other = semaphore->sync_to[fence->ring];
-        semaphore->sync_to[fence->ring] = radeon_fence_later(fence, other);
-}
-
-/**
- * radeon_semaphore_sync_to - use the semaphore to sync to a reservation object
- *
- * @sema: semaphore object to add fence from reservation object to
- * @resv: reservation object with embedded fence
- * @shared: true if we should onyl sync to the exclusive fence
- *
- * Sync to the fence using this semaphore object
- */
-int radeon_semaphore_sync_resv(struct radeon_device *rdev,
-                              struct radeon_semaphore *sema,
-                              struct reservation_object *resv,
-                              bool shared)
-{
-       struct reservation_object_list *flist;
-       struct fence *f;
-       struct radeon_fence *fence;
-       unsigned i;
-       int r = 0;
-
-       /* always sync to the exclusive fence */
-       f = reservation_object_get_excl(resv);
-       fence = f ? to_radeon_fence(f) : NULL;
-       if (fence && fence->rdev == rdev)
-               radeon_semaphore_sync_fence(sema, fence);
-       else if (f)
-               r = fence_wait(f, true);
-
-       flist = reservation_object_get_list(resv);
-       if (shared || !flist || r)
-               return r;
-
-       for (i = 0; i < flist->shared_count; ++i) {
-               f = rcu_dereference_protected(flist->shared[i],
-                                             reservation_object_held(resv));
-               fence = to_radeon_fence(f);
-               if (fence && fence->rdev == rdev)
-                       radeon_semaphore_sync_fence(sema, fence);
-               else
-                       r = fence_wait(f, true);
-
-               if (r)
-                       break;
-       }
-       return r;
-}
-
-/**
- * radeon_semaphore_sync_rings - sync ring to all registered fences
- *
- * @rdev: radeon_device pointer
- * @semaphore: semaphore object to use for sync
- * @ring: ring that needs sync
- *
- * Ensure that all registered fences are signaled before letting
- * the ring continue. The caller must hold the ring lock.
- */
-int radeon_semaphore_sync_rings(struct radeon_device *rdev,
-                               struct radeon_semaphore *semaphore,
-                               int ring)
-{
-       unsigned count = 0;
-       int i, r;
-
-        for (i = 0; i < RADEON_NUM_RINGS; ++i) {
-               struct radeon_fence *fence = semaphore->sync_to[i];
-
-               /* check if we really need to sync */
-                if (!radeon_fence_need_sync(fence, ring))
-                       continue;
-
-               /* prevent GPU deadlocks */
-               if (!rdev->ring[i].ready) {
-                       dev_err(rdev->dev, "Syncing to a disabled ring!");
-                       return -EINVAL;
-               }
-
-               if (++count > RADEON_NUM_SYNCS) {
-                       /* not enough room, wait manually */
-                       r = radeon_fence_wait(fence, false);
-                       if (r)
-                               return r;
-                       continue;
-               }
-
-               /* allocate enough space for sync command */
-               r = radeon_ring_alloc(rdev, &rdev->ring[i], 16);
-               if (r) {
-                       return r;
-               }
-
-               /* emit the signal semaphore */
-               if (!radeon_semaphore_emit_signal(rdev, i, semaphore)) {
-                       /* signaling wasn't successful wait manually */
-                       radeon_ring_undo(&rdev->ring[i]);
-                       r = radeon_fence_wait(fence, false);
-                       if (r)
-                               return r;
-                       continue;
-               }
-
-               /* we assume caller has already allocated space on waiters ring */
-               if (!radeon_semaphore_emit_wait(rdev, ring, semaphore)) {
-                       /* waiting wasn't successful wait manually */
-                       radeon_ring_undo(&rdev->ring[i]);
-                       r = radeon_fence_wait(fence, false);
-                       if (r)
-                               return r;
-                       continue;
-               }
-
-               radeon_ring_commit(rdev, &rdev->ring[i], false);
-               radeon_fence_note_sync(fence, ring);
-
-               semaphore->gpu_addr += 8;
-       }
-
-       return 0;
-}
-
 void radeon_semaphore_free(struct radeon_device *rdev,
                           struct radeon_semaphore **semaphore,
                           struct radeon_fence *fence)
diff --git a/drivers/gpu/drm/radeon/radeon_sync.c b/drivers/gpu/drm/radeon/radeon_sync.c
new file mode 100644 (file)
index 0000000..02ac8a1
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors:
+ *    Christian König <christian.koenig@amd.com>
+ */
+
+#include <drm/drmP.h>
+#include "radeon.h"
+#include "radeon_trace.h"
+
+/**
+ * radeon_sync_create - zero init sync object
+ *
+ * @sync: sync object to initialize
+ *
+ * Just clear the sync object for now.
+ */
+void radeon_sync_create(struct radeon_sync *sync)
+{
+       unsigned i;
+
+       for (i = 0; i < RADEON_NUM_SYNCS; ++i)
+               sync->semaphores[i] = NULL;
+
+       for (i = 0; i < RADEON_NUM_RINGS; ++i)
+               sync->sync_to[i] = NULL;
+
+       sync->last_vm_update = NULL;
+}
+
+/**
+ * radeon_sync_fence - use the semaphore to sync to a fence
+ *
+ * @sync: sync object to add fence to
+ * @fence: fence to sync to
+ *
+ * Sync to the fence using the semaphore objects
+ */
+void radeon_sync_fence(struct radeon_sync *sync,
+                      struct radeon_fence *fence)
+{
+       struct radeon_fence *other;
+
+       if (!fence)
+               return;
+
+       other = sync->sync_to[fence->ring];
+       sync->sync_to[fence->ring] = radeon_fence_later(fence, other);
+
+       if (fence->is_vm_update) {
+               other = sync->last_vm_update;
+               sync->last_vm_update = radeon_fence_later(fence, other);
+       }
+}
+
+/**
+ * radeon_sync_resv - use the semaphores to sync to a reservation object
+ *
+ * @sync: sync object to add fences from reservation object to
+ * @resv: reservation object with embedded fence
+ * @shared: true if we should only sync to the exclusive fence
+ *
+ * Sync to the fence using the semaphore objects
+ */
+int radeon_sync_resv(struct radeon_device *rdev,
+                    struct radeon_sync *sync,
+                    struct reservation_object *resv,
+                    bool shared)
+{
+       struct reservation_object_list *flist;
+       struct fence *f;
+       struct radeon_fence *fence;
+       unsigned i;
+       int r = 0;
+
+       /* always sync to the exclusive fence */
+       f = reservation_object_get_excl(resv);
+       fence = f ? to_radeon_fence(f) : NULL;
+       if (fence && fence->rdev == rdev)
+               radeon_sync_fence(sync, fence);
+       else if (f)
+               r = fence_wait(f, true);
+
+       flist = reservation_object_get_list(resv);
+       if (shared || !flist || r)
+               return r;
+
+       for (i = 0; i < flist->shared_count; ++i) {
+               f = rcu_dereference_protected(flist->shared[i],
+                                             reservation_object_held(resv));
+               fence = to_radeon_fence(f);
+               if (fence && fence->rdev == rdev)
+                       radeon_sync_fence(sync, fence);
+               else
+                       r = fence_wait(f, true);
+
+               if (r)
+                       break;
+       }
+       return r;
+}
+
+/**
+ * radeon_sync_rings - sync ring to all registered fences
+ *
+ * @rdev: radeon_device pointer
+ * @sync: sync object to use
+ * @ring: ring that needs sync
+ *
+ * Ensure that all registered fences are signaled before letting
+ * the ring continue. The caller must hold the ring lock.
+ */
+int radeon_sync_rings(struct radeon_device *rdev,
+                     struct radeon_sync *sync,
+                     int ring)
+{
+       unsigned count = 0;
+       int i, r;
+
+       for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+               struct radeon_fence *fence = sync->sync_to[i];
+               struct radeon_semaphore *semaphore;
+
+               /* check if we really need to sync */
+               if (!radeon_fence_need_sync(fence, ring))
+                       continue;
+
+               /* prevent GPU deadlocks */
+               if (!rdev->ring[i].ready) {
+                       dev_err(rdev->dev, "Syncing to a disabled ring!");
+                       return -EINVAL;
+               }
+
+               if (count >= RADEON_NUM_SYNCS) {
+                       /* not enough room, wait manually */
+                       r = radeon_fence_wait(fence, false);
+                       if (r)
+                               return r;
+                       continue;
+               }
+               r = radeon_semaphore_create(rdev, &semaphore);
+               if (r)
+                       return r;
+
+               sync->semaphores[count++] = semaphore;
+
+               /* allocate enough space for sync command */
+               r = radeon_ring_alloc(rdev, &rdev->ring[i], 16);
+               if (r)
+                       return r;
+
+               /* emit the signal semaphore */
+               if (!radeon_semaphore_emit_signal(rdev, i, semaphore)) {
+                       /* signaling wasn't successful wait manually */
+                       radeon_ring_undo(&rdev->ring[i]);
+                       r = radeon_fence_wait(fence, false);
+                       if (r)
+                               return r;
+                       continue;
+               }
+
+               /* we assume caller has already allocated space on waiters ring */
+               if (!radeon_semaphore_emit_wait(rdev, ring, semaphore)) {
+                       /* waiting wasn't successful wait manually */
+                       radeon_ring_undo(&rdev->ring[i]);
+                       r = radeon_fence_wait(fence, false);
+                       if (r)
+                               return r;
+                       continue;
+               }
+
+               radeon_ring_commit(rdev, &rdev->ring[i], false);
+               radeon_fence_note_sync(fence, ring);
+       }
+
+       return 0;
+}
+
+/**
+ * radeon_sync_free - free the sync object
+ *
+ * @rdev: radeon_device pointer
+ * @sync: sync object to use
+ * @fence: fence to use for the free
+ *
+ * Free the sync object by freeing all semaphores in it.
+ */
+void radeon_sync_free(struct radeon_device *rdev,
+                     struct radeon_sync *sync,
+                     struct radeon_fence *fence)
+{
+       unsigned i;
+
+       for (i = 0; i < RADEON_NUM_SYNCS; ++i)
+               radeon_semaphore_free(rdev, &sync->semaphores[i], fence);
+}
index 8624979afb65f55ecba4ffb888aa09d0b3c8b39d..cbe7b32d181c2f3bf2972b14f12c72597d3e15f5 100644 (file)
@@ -198,7 +198,30 @@ static void radeon_evict_flags(struct ttm_buffer_object *bo,
        case TTM_PL_VRAM:
                if (rbo->rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready == false)
                        radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_CPU);
-               else
+               else if (rbo->rdev->mc.visible_vram_size < rbo->rdev->mc.real_vram_size &&
+                        bo->mem.start < (rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT)) {
+                       unsigned fpfn = rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
+                       int i;
+
+                       /* Try evicting to the CPU inaccessible part of VRAM
+                        * first, but only set GTT as busy placement, so this
+                        * BO will be evicted to GTT rather than causing other
+                        * BOs to be evicted from VRAM
+                        */
+                       radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM |
+                                                        RADEON_GEM_DOMAIN_GTT);
+                       rbo->placement.num_busy_placement = 0;
+                       for (i = 0; i < rbo->placement.num_placement; i++) {
+                               if (rbo->placements[i].flags & TTM_PL_FLAG_VRAM) {
+                                       if (rbo->placements[0].fpfn < fpfn)
+                                               rbo->placements[0].fpfn = fpfn;
+                               } else {
+                                       rbo->placement.busy_placement =
+                                               &rbo->placements[i];
+                                       rbo->placement.num_busy_placement = 1;
+                               }
+                       }
+               } else
                        radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT);
                break;
        case TTM_PL_TT:
index dfde266529e2a787fd953a85bb12c4673e448d37..0b10f3a03ce2f20ac66103c932f4d6a51c8fd743 100644 (file)
@@ -143,7 +143,7 @@ struct radeon_cs_reloc *radeon_vm_get_bos(struct radeon_device *rdev,
        list[0].prefered_domains = RADEON_GEM_DOMAIN_VRAM;
        list[0].allowed_domains = RADEON_GEM_DOMAIN_VRAM;
        list[0].tv.bo = &vm->page_directory->tbo;
-       list[0].tv.shared = false;
+       list[0].tv.shared = true;
        list[0].tiling_flags = 0;
        list[0].handle = 0;
        list_add(&list[0].tv.head, head);
@@ -157,7 +157,7 @@ struct radeon_cs_reloc *radeon_vm_get_bos(struct radeon_device *rdev,
                list[idx].prefered_domains = RADEON_GEM_DOMAIN_VRAM;
                list[idx].allowed_domains = RADEON_GEM_DOMAIN_VRAM;
                list[idx].tv.bo = &list[idx].robj->tbo;
-               list[idx].tv.shared = false;
+               list[idx].tv.shared = true;
                list[idx].tiling_flags = 0;
                list[idx].handle = 0;
                list_add(&list[idx++].tv.head, head);
@@ -182,15 +182,18 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
                                       struct radeon_vm *vm, int ring)
 {
        struct radeon_fence *best[RADEON_NUM_RINGS] = {};
+       struct radeon_vm_id *vm_id = &vm->ids[ring];
+
        unsigned choices[2] = {};
        unsigned i;
 
        /* check if the id is still valid */
-       if (vm->last_id_use && vm->last_id_use == rdev->vm_manager.active[vm->id])
+       if (vm_id->id && vm_id->last_id_use &&
+           vm_id->last_id_use == rdev->vm_manager.active[vm_id->id])
                return NULL;
 
        /* we definately need to flush */
-       radeon_fence_unref(&vm->last_flush);
+       vm_id->pd_gpu_addr = ~0ll;
 
        /* skip over VMID 0, since it is the system VM */
        for (i = 1; i < rdev->vm_manager.nvm; ++i) {
@@ -198,8 +201,8 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
 
                if (fence == NULL) {
                        /* found a free one */
-                       vm->id = i;
-                       trace_radeon_vm_grab_id(vm->id, ring);
+                       vm_id->id = i;
+                       trace_radeon_vm_grab_id(i, ring);
                        return NULL;
                }
 
@@ -211,8 +214,8 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
 
        for (i = 0; i < 2; ++i) {
                if (choices[i]) {
-                       vm->id = choices[i];
-                       trace_radeon_vm_grab_id(vm->id, ring);
+                       vm_id->id = choices[i];
+                       trace_radeon_vm_grab_id(choices[i], ring);
                        return rdev->vm_manager.active[choices[i]];
                }
        }
@@ -228,6 +231,7 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
  * @rdev: radeon_device pointer
  * @vm: vm we want to flush
  * @ring: ring to use for flush
+ * @updates: last vm update that is waited for
  *
  * Flush the vm (cayman+).
  *
@@ -235,15 +239,21 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
  */
 void radeon_vm_flush(struct radeon_device *rdev,
                     struct radeon_vm *vm,
-                    int ring)
+                    int ring, struct radeon_fence *updates)
 {
        uint64_t pd_addr = radeon_bo_gpu_offset(vm->page_directory);
+       struct radeon_vm_id *vm_id = &vm->ids[ring];
+
+       if (pd_addr != vm_id->pd_gpu_addr || !vm_id->flushed_updates ||
+           radeon_fence_is_earlier(vm_id->flushed_updates, updates)) {
+
+               trace_radeon_vm_flush(pd_addr, ring, vm->ids[ring].id);
+               radeon_fence_unref(&vm_id->flushed_updates);
+               vm_id->flushed_updates = radeon_fence_ref(updates);
+               vm_id->pd_gpu_addr = pd_addr;
+               radeon_ring_vm_flush(rdev, &rdev->ring[ring],
+                                    vm_id->id, vm_id->pd_gpu_addr);
 
-       /* if we can't remember our last VM flush then flush now! */
-       if (!vm->last_flush || pd_addr != vm->pd_gpu_addr) {
-               trace_radeon_vm_flush(pd_addr, ring, vm->id);
-               vm->pd_gpu_addr = pd_addr;
-               radeon_ring_vm_flush(rdev, ring, vm);
        }
 }
 
@@ -263,18 +273,13 @@ void radeon_vm_fence(struct radeon_device *rdev,
                     struct radeon_vm *vm,
                     struct radeon_fence *fence)
 {
-       radeon_fence_unref(&vm->fence);
-       vm->fence = radeon_fence_ref(fence);
+       unsigned vm_id = vm->ids[fence->ring].id;
 
-       radeon_fence_unref(&rdev->vm_manager.active[vm->id]);
-       rdev->vm_manager.active[vm->id] = radeon_fence_ref(fence);
+       radeon_fence_unref(&rdev->vm_manager.active[vm_id]);
+       rdev->vm_manager.active[vm_id] = radeon_fence_ref(fence);
 
-       radeon_fence_unref(&vm->last_id_use);
-       vm->last_id_use = radeon_fence_ref(fence);
-
-        /* we just flushed the VM, remember that */
-        if (!vm->last_flush)
-                vm->last_flush = radeon_fence_ref(fence);
+       radeon_fence_unref(&vm->ids[fence->ring].last_id_use);
+       vm->ids[fence->ring].last_id_use = radeon_fence_ref(fence);
 }
 
 /**
@@ -387,35 +392,25 @@ static void radeon_vm_set_pages(struct radeon_device *rdev,
 static int radeon_vm_clear_bo(struct radeon_device *rdev,
                              struct radeon_bo *bo)
 {
-        struct ttm_validate_buffer tv;
-        struct ww_acquire_ctx ticket;
-        struct list_head head;
        struct radeon_ib ib;
        unsigned entries;
        uint64_t addr;
        int r;
 
-        memset(&tv, 0, sizeof(tv));
-        tv.bo = &bo->tbo;
-       tv.shared = false;
-
-        INIT_LIST_HEAD(&head);
-        list_add(&tv.head, &head);
-
-        r = ttm_eu_reserve_buffers(&ticket, &head, true);
-        if (r)
+       r = radeon_bo_reserve(bo, false);
+       if (r)
                return r;
 
-        r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
-        if (r)
-                goto error;
+       r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
+       if (r)
+               goto error_unreserve;
 
        addr = radeon_bo_gpu_offset(bo);
        entries = radeon_bo_size(bo) / 8;
 
        r = radeon_ib_get(rdev, R600_RING_TYPE_DMA_INDEX, &ib, NULL, 256);
        if (r)
-                goto error;
+               goto error_unreserve;
 
        ib.length_dw = 0;
 
@@ -425,15 +420,16 @@ static int radeon_vm_clear_bo(struct radeon_device *rdev,
 
        r = radeon_ib_schedule(rdev, &ib, NULL, false);
        if (r)
-                goto error;
+               goto error_free;
 
-       ttm_eu_fence_buffer_objects(&ticket, &head, &ib.fence->base);
-       radeon_ib_free(rdev, &ib);
+       ib.fence->is_vm_update = true;
+       radeon_bo_fence(bo, ib.fence, false);
 
-       return 0;
+error_free:
+       radeon_ib_free(rdev, &ib);
 
-error:
-       ttm_eu_backoff_reservation(&ticket, &head);
+error_unreserve:
+       radeon_bo_unreserve(bo);
        return r;
 }
 
@@ -449,7 +445,7 @@ error:
  * Validate and set the offset requested within the vm address space.
  * Returns 0 for success, error for failure.
  *
- * Object has to be reserved!
+ * Object has to be reserved and gets unreserved by this function!
  */
 int radeon_vm_bo_set_addr(struct radeon_device *rdev,
                          struct radeon_bo_va *bo_va,
@@ -575,7 +571,7 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
        }
 
        mutex_unlock(&vm->mutex);
-       return radeon_bo_reserve(bo_va->bo, false);
+       return 0;
 }
 
 /**
@@ -699,17 +695,15 @@ int radeon_vm_update_page_directory(struct radeon_device *rdev,
        if (ib.length_dw != 0) {
                radeon_asic_vm_pad_ib(rdev, &ib);
 
-               radeon_semaphore_sync_resv(rdev, ib.semaphore, pd->tbo.resv, false);
-               radeon_semaphore_sync_fence(ib.semaphore, vm->last_id_use);
+               radeon_sync_resv(rdev, &ib.sync, pd->tbo.resv, true);
                WARN_ON(ib.length_dw > ndw);
                r = radeon_ib_schedule(rdev, &ib, NULL, false);
                if (r) {
                        radeon_ib_free(rdev, &ib);
                        return r;
                }
-               radeon_fence_unref(&vm->fence);
-               vm->fence = radeon_fence_ref(ib.fence);
-               radeon_fence_unref(&vm->last_flush);
+               ib.fence->is_vm_update = true;
+               radeon_bo_fence(pd, ib.fence, false);
        }
        radeon_ib_free(rdev, &ib);
 
@@ -826,7 +820,7 @@ static void radeon_vm_update_ptes(struct radeon_device *rdev,
                unsigned nptes;
                uint64_t pte;
 
-               radeon_semaphore_sync_resv(rdev, ib->semaphore, pt->tbo.resv, false);
+               radeon_sync_resv(rdev, &ib->sync, pt->tbo.resv, true);
 
                if ((addr & ~mask) == (end & ~mask))
                        nptes = end - addr;
@@ -862,6 +856,31 @@ static void radeon_vm_update_ptes(struct radeon_device *rdev,
        }
 }
 
+/**
+ * radeon_vm_fence_pts - fence page tables after an update
+ *
+ * @vm: requested vm
+ * @start: start of GPU address range
+ * @end: end of GPU address range
+ * @fence: fence to use
+ *
+ * Fence the page tables in the range @start - @end (cayman+).
+ *
+ * Global and local mutex must be locked!
+ */
+static void radeon_vm_fence_pts(struct radeon_vm *vm,
+                               uint64_t start, uint64_t end,
+                               struct radeon_fence *fence)
+{
+       unsigned i;
+
+       start >>= radeon_vm_block_size;
+       end >>= radeon_vm_block_size;
+
+       for (i = start; i <= end; ++i)
+               radeon_bo_fence(vm->page_tables[i].bo, fence, false);
+}
+
 /**
  * radeon_vm_bo_update - map a bo into the vm page table
  *
@@ -961,6 +980,13 @@ int radeon_vm_bo_update(struct radeon_device *rdev,
                return r;
        ib.length_dw = 0;
 
+       if (!(bo_va->flags & RADEON_VM_PAGE_VALID)) {
+               unsigned i;
+
+               for (i = 0; i < RADEON_NUM_RINGS; ++i)
+                       radeon_sync_fence(&ib.sync, vm->ids[i].last_id_use);
+       }
+
        radeon_vm_update_ptes(rdev, vm, &ib, bo_va->it.start,
                              bo_va->it.last + 1, addr,
                              radeon_vm_page_flags(bo_va->flags));
@@ -968,16 +994,16 @@ int radeon_vm_bo_update(struct radeon_device *rdev,
        radeon_asic_vm_pad_ib(rdev, &ib);
        WARN_ON(ib.length_dw > ndw);
 
-       radeon_semaphore_sync_fence(ib.semaphore, vm->fence);
        r = radeon_ib_schedule(rdev, &ib, NULL, false);
        if (r) {
                radeon_ib_free(rdev, &ib);
                return r;
        }
-       radeon_fence_unref(&vm->fence);
-       vm->fence = radeon_fence_ref(ib.fence);
+       ib.fence->is_vm_update = true;
+       radeon_vm_fence_pts(vm, bo_va->it.start, bo_va->it.last + 1, ib.fence);
+       radeon_fence_unref(&bo_va->last_pt_update);
+       bo_va->last_pt_update = radeon_fence_ref(ib.fence);
        radeon_ib_free(rdev, &ib);
-       radeon_fence_unref(&vm->last_flush);
 
        return 0;
 }
@@ -1002,6 +1028,7 @@ int radeon_vm_clear_freed(struct radeon_device *rdev,
        list_for_each_entry_safe(bo_va, tmp, &vm->freed, vm_status) {
                r = radeon_vm_bo_update(rdev, bo_va, NULL);
                radeon_bo_unref(&bo_va->bo);
+               radeon_fence_unref(&bo_va->last_pt_update);
                kfree(bo_va);
                if (r)
                        return r;
@@ -1060,6 +1087,7 @@ void radeon_vm_bo_rmv(struct radeon_device *rdev,
                bo_va->bo = radeon_bo_ref(bo_va->bo);
                list_add(&bo_va->vm_status, &vm->freed);
        } else {
+               radeon_fence_unref(&bo_va->last_pt_update);
                kfree(bo_va);
        }
 
@@ -1103,13 +1131,14 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
        const unsigned align = min(RADEON_VM_PTB_ALIGN_SIZE,
                RADEON_VM_PTE_COUNT * 8);
        unsigned pd_size, pd_entries, pts_size;
-       int r;
+       int i, r;
 
-       vm->id = 0;
        vm->ib_bo_va = NULL;
-       vm->fence = NULL;
-       vm->last_flush = NULL;
-       vm->last_id_use = NULL;
+       for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+               vm->ids[i].id = 0;
+               vm->ids[i].flushed_updates = NULL;
+               vm->ids[i].last_id_use = NULL;
+       }
        mutex_init(&vm->mutex);
        vm->va = RB_ROOT;
        INIT_LIST_HEAD(&vm->invalidated);
@@ -1165,11 +1194,13 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
                if (!r) {
                        list_del_init(&bo_va->bo_list);
                        radeon_bo_unreserve(bo_va->bo);
+                       radeon_fence_unref(&bo_va->last_pt_update);
                        kfree(bo_va);
                }
        }
        list_for_each_entry_safe(bo_va, tmp, &vm->freed, vm_status) {
                radeon_bo_unref(&bo_va->bo);
+               radeon_fence_unref(&bo_va->last_pt_update);
                kfree(bo_va);
        }
 
@@ -1179,9 +1210,10 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
 
        radeon_bo_unref(&vm->page_directory);
 
-       radeon_fence_unref(&vm->fence);
-       radeon_fence_unref(&vm->last_flush);
-       radeon_fence_unref(&vm->last_id_use);
+       for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+               radeon_fence_unref(&vm->ids[i].flushed_updates);
+               radeon_fence_unref(&vm->ids[i].last_id_use);
+       }
 
        mutex_destroy(&vm->mutex);
 }
index 7f34bad2e724d6e657203cfde55f85ddb48fa8da..acff6e09cc40b767d30582624f9187e21d7aad2e 100644 (file)
@@ -44,31 +44,27 @@ struct radeon_fence *rv770_copy_dma(struct radeon_device *rdev,
                                    unsigned num_gpu_pages,
                                    struct reservation_object *resv)
 {
-       struct radeon_semaphore *sem = NULL;
        struct radeon_fence *fence;
+       struct radeon_sync sync;
        int ring_index = rdev->asic->copy.dma_ring_index;
        struct radeon_ring *ring = &rdev->ring[ring_index];
        u32 size_in_dw, cur_size_in_dw;
        int i, num_loops;
        int r = 0;
 
-       r = radeon_semaphore_create(rdev, &sem);
-       if (r) {
-               DRM_ERROR("radeon: moving bo (%d).\n", r);
-               return ERR_PTR(r);
-       }
+       radeon_sync_create(&sync);
 
        size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4;
        num_loops = DIV_ROUND_UP(size_in_dw, 0xFFFF);
        r = radeon_ring_lock(rdev, ring, num_loops * 5 + 8);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
-               radeon_semaphore_free(rdev, &sem, NULL);
+               radeon_sync_free(rdev, &sync, NULL);
                return ERR_PTR(r);
        }
 
-       radeon_semaphore_sync_resv(rdev, sem, resv, false);
-       radeon_semaphore_sync_rings(rdev, sem, ring->idx);
+       radeon_sync_resv(rdev, &sync, resv, false);
+       radeon_sync_rings(rdev, &sync, ring->idx);
 
        for (i = 0; i < num_loops; i++) {
                cur_size_in_dw = size_in_dw;
@@ -87,12 +83,12 @@ struct radeon_fence *rv770_copy_dma(struct radeon_device *rdev,
        r = radeon_fence_emit(rdev, &fence, ring->idx);
        if (r) {
                radeon_ring_unlock_undo(rdev, ring);
-               radeon_semaphore_free(rdev, &sem, NULL);
+               radeon_sync_free(rdev, &sync, NULL);
                return ERR_PTR(r);
        }
 
        radeon_ring_unlock_commit(rdev, ring, false);
-       radeon_semaphore_free(rdev, &sem, fence);
+       radeon_sync_free(rdev, &sync, fence);
 
        return fence;
 }
index 7d5083dc4acbad7d333766195586c3b5562a5f58..60df444bd0756fbe42b5a5dab1072f47c5c73a3a 100644 (file)
@@ -3365,6 +3365,7 @@ void si_fence_ring_emit(struct radeon_device *rdev,
 void si_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
 {
        struct radeon_ring *ring = &rdev->ring[ib->ring];
+       unsigned vm_id = ib->vm ? ib->vm->ids[ib->ring].id : 0;
        u32 header;
 
        if (ib->is_const_ib) {
@@ -3400,14 +3401,13 @@ void si_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
 #endif
                          (ib->gpu_addr & 0xFFFFFFFC));
        radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF);
-       radeon_ring_write(ring, ib->length_dw |
-                         (ib->vm ? (ib->vm->id << 24) : 0));
+       radeon_ring_write(ring, ib->length_dw | (vm_id << 24));
 
        if (!ib->is_const_ib) {
                /* flush read cache over gart for this vmid */
                radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
                radeon_ring_write(ring, (CP_COHER_CNTL2 - PACKET3_SET_CONFIG_REG_START) >> 2);
-               radeon_ring_write(ring, ib->vm ? ib->vm->id : 0);
+               radeon_ring_write(ring, vm_id);
                radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3));
                radeon_ring_write(ring, PACKET3_TCL1_ACTION_ENA |
                                  PACKET3_TC_ACTION_ENA |
@@ -5023,27 +5023,23 @@ static void si_vm_decode_fault(struct radeon_device *rdev,
               block, mc_id);
 }
 
-void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
+void si_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
+                unsigned vm_id, uint64_t pd_addr)
 {
-       struct radeon_ring *ring = &rdev->ring[ridx];
-
-       if (vm == NULL)
-               return;
-
        /* write new base address */
        radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
        radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) |
                                 WRITE_DATA_DST_SEL(0)));
 
-       if (vm->id < 8) {
+       if (vm_id < 8) {
                radeon_ring_write(ring,
-                                 (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2);
+                                 (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2)) >> 2);
        } else {
                radeon_ring_write(ring,
-                                 (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2);
+                                 (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm_id - 8) << 2)) >> 2);
        }
        radeon_ring_write(ring, 0);
-       radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
+       radeon_ring_write(ring, pd_addr >> 12);
 
        /* flush hdp cache */
        radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
@@ -5059,7 +5055,7 @@ void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
                                 WRITE_DATA_DST_SEL(0)));
        radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
        radeon_ring_write(ring, 0);
-       radeon_ring_write(ring, 1 << vm->id);
+       radeon_ring_write(ring, 1 << vm_id);
 
        /* sync PFP to ME, otherwise we might get invalid PFP reads */
        radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
index b58f12b762d797c3c4db418712987cf0da43718d..f5cc777e1c5f142ff00b383e3863b70b47a96b3e 100644 (file)
@@ -185,20 +185,17 @@ void si_dma_vm_set_pages(struct radeon_device *rdev,
        }
 }
 
-void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
-{
-       struct radeon_ring *ring = &rdev->ring[ridx];
-
-       if (vm == NULL)
-               return;
+void si_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
+                    unsigned vm_id, uint64_t pd_addr)
 
+{
        radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0));
-       if (vm->id < 8) {
-               radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2));
+       if (vm_id < 8) {
+               radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2)) >> 2));
        } else {
-               radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2));
+               radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm_id - 8) << 2)) >> 2));
        }
-       radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
+       radeon_ring_write(ring, pd_addr >> 12);
 
        /* flush hdp cache */
        radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0));
@@ -208,7 +205,7 @@ void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
        /* bits 0-7 are the VM contexts0-7 */
        radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0));
        radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2));
-       radeon_ring_write(ring, 1 << vm->id);
+       radeon_ring_write(ring, 1 << vm_id);
 }
 
 /**
@@ -229,31 +226,27 @@ struct radeon_fence *si_copy_dma(struct radeon_device *rdev,
                                 unsigned num_gpu_pages,
                                 struct reservation_object *resv)
 {
-       struct radeon_semaphore *sem = NULL;
        struct radeon_fence *fence;
+       struct radeon_sync sync;
        int ring_index = rdev->asic->copy.dma_ring_index;
        struct radeon_ring *ring = &rdev->ring[ring_index];
        u32 size_in_bytes, cur_size_in_bytes;
        int i, num_loops;
        int r = 0;
 
-       r = radeon_semaphore_create(rdev, &sem);
-       if (r) {
-               DRM_ERROR("radeon: moving bo (%d).\n", r);
-               return ERR_PTR(r);
-       }
+       radeon_sync_create(&sync);
 
        size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
        num_loops = DIV_ROUND_UP(size_in_bytes, 0xfffff);
        r = radeon_ring_lock(rdev, ring, num_loops * 5 + 11);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
-               radeon_semaphore_free(rdev, &sem, NULL);
+               radeon_sync_free(rdev, &sync, NULL);
                return ERR_PTR(r);
        }
 
-       radeon_semaphore_sync_resv(rdev, sem, resv, false);
-       radeon_semaphore_sync_rings(rdev, sem, ring->idx);
+       radeon_sync_resv(rdev, &sync, resv, false);
+       radeon_sync_rings(rdev, &sync, ring->idx);
 
        for (i = 0; i < num_loops; i++) {
                cur_size_in_bytes = size_in_bytes;
@@ -272,12 +265,12 @@ struct radeon_fence *si_copy_dma(struct radeon_device *rdev,
        r = radeon_fence_emit(rdev, &fence, ring->idx);
        if (r) {
                radeon_ring_unlock_undo(rdev, ring);
-               radeon_semaphore_free(rdev, &sem, NULL);
+               radeon_sync_free(rdev, &sync, NULL);
                return ERR_PTR(r);
        }
 
        radeon_ring_unlock_commit(rdev, ring, false);
-       radeon_semaphore_free(rdev, &sem, fence);
+       radeon_sync_free(rdev, &sync, fence);
 
        return fence;
 }
index 676e6c2ba90a3159f1c888c063837fca77647376..cf4c420b55727083696a589631b0ac405b5567fc 100644 (file)
@@ -3396,6 +3396,15 @@ static int si_process_firmware_header(struct radeon_device *rdev)
 
        si_pi->mc_reg_table_start = tmp;
 
+       ret = si_read_smc_sram_dword(rdev,
+                                    SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+                                    SISLANDS_SMC_FIRMWARE_HEADER_fanTable,
+                                    &tmp, si_pi->sram_end);
+       if (ret)
+               return ret;
+
+       si_pi->fan_table_start = tmp;
+
        ret = si_read_smc_sram_dword(rdev,
                                     SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
                                     SISLANDS_SMC_FIRMWARE_HEADER_mcArbDramAutoRefreshTable,
@@ -5817,8 +5826,33 @@ void si_dpm_setup_asic(struct radeon_device *rdev)
        si_enable_acpi_power_management(rdev);
 }
 
-static int si_set_thermal_temperature_range(struct radeon_device *rdev,
-                                       int min_temp, int max_temp)
+static int si_thermal_enable_alert(struct radeon_device *rdev,
+                                  bool enable)
+{
+       u32 thermal_int = RREG32(CG_THERMAL_INT);
+
+       if (enable) {
+               PPSMC_Result result;
+
+               thermal_int &= ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
+               WREG32(CG_THERMAL_INT, thermal_int);
+               rdev->irq.dpm_thermal = false;
+               result = si_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
+               if (result != PPSMC_Result_OK) {
+                       DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
+                       return -EINVAL;
+               }
+       } else {
+               thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
+               WREG32(CG_THERMAL_INT, thermal_int);
+               rdev->irq.dpm_thermal = true;
+       }
+
+       return 0;
+}
+
+static int si_thermal_set_temperature_range(struct radeon_device *rdev,
+                                           int min_temp, int max_temp)
 {
        int low_temp = 0 * 1000;
        int high_temp = 255 * 1000;
@@ -5842,6 +5876,309 @@ static int si_set_thermal_temperature_range(struct radeon_device *rdev,
        return 0;
 }
 
+static void si_fan_ctrl_set_static_mode(struct radeon_device *rdev, u32 mode)
+{
+       struct si_power_info *si_pi = si_get_pi(rdev);
+       u32 tmp;
+
+       if (si_pi->fan_ctrl_is_in_default_mode) {
+               tmp = (RREG32(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK) >> FDO_PWM_MODE_SHIFT;
+               si_pi->fan_ctrl_default_mode = tmp;
+               tmp = (RREG32(CG_FDO_CTRL2) & TMIN_MASK) >> TMIN_SHIFT;
+               si_pi->t_min = tmp;
+               si_pi->fan_ctrl_is_in_default_mode = false;
+       }
+
+       tmp = RREG32(CG_FDO_CTRL2) & ~TMIN_MASK;
+       tmp |= TMIN(0);
+       WREG32(CG_FDO_CTRL2, tmp);
+
+       tmp = RREG32(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK;
+       tmp |= FDO_PWM_MODE(mode);
+       WREG32(CG_FDO_CTRL2, tmp);
+}
+
+static int si_thermal_setup_fan_table(struct radeon_device *rdev)
+{
+       struct si_power_info *si_pi = si_get_pi(rdev);
+       PP_SIslands_FanTable fan_table = { FDO_MODE_HARDWARE };
+       u32 duty100;
+       u32 t_diff1, t_diff2, pwm_diff1, pwm_diff2;
+       u16 fdo_min, slope1, slope2;
+       u32 reference_clock, tmp;
+       int ret;
+       u64 tmp64;
+
+       if (!si_pi->fan_table_start) {
+               rdev->pm.dpm.fan.ucode_fan_control = false;
+               return 0;
+       }
+
+       duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
+
+       if (duty100 == 0) {
+               rdev->pm.dpm.fan.ucode_fan_control = false;
+               return 0;
+       }
+
+       tmp64 = (u64)rdev->pm.dpm.fan.pwm_min * duty100;
+       do_div(tmp64, 10000);
+       fdo_min = (u16)tmp64;
+
+       t_diff1 = rdev->pm.dpm.fan.t_med - rdev->pm.dpm.fan.t_min;
+       t_diff2 = rdev->pm.dpm.fan.t_high - rdev->pm.dpm.fan.t_med;
+
+       pwm_diff1 = rdev->pm.dpm.fan.pwm_med - rdev->pm.dpm.fan.pwm_min;
+       pwm_diff2 = rdev->pm.dpm.fan.pwm_high - rdev->pm.dpm.fan.pwm_med;
+
+       slope1 = (u16)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
+       slope2 = (u16)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
+
+       fan_table.slope1 = cpu_to_be16(slope1);
+       fan_table.slope2 = cpu_to_be16(slope2);
+
+       fan_table.fdo_min = cpu_to_be16(fdo_min);
+
+       fan_table.hys_down = cpu_to_be16(rdev->pm.dpm.fan.t_hyst);
+
+       fan_table.hys_up = cpu_to_be16(1);
+
+       fan_table.hys_slope = cpu_to_be16(1);
+
+       fan_table.temp_resp_lim = cpu_to_be16(5);
+
+       reference_clock = radeon_get_xclk(rdev);
+
+       fan_table.refresh_period = cpu_to_be32((rdev->pm.dpm.fan.cycle_delay *
+                                               reference_clock) / 1600);
+
+       fan_table.fdo_max = cpu_to_be16((u16)duty100);
+
+       tmp = (RREG32(CG_MULT_THERMAL_CTRL) & TEMP_SEL_MASK) >> TEMP_SEL_SHIFT;
+       fan_table.temp_src = (uint8_t)tmp;
+
+       ret = si_copy_bytes_to_smc(rdev,
+                                  si_pi->fan_table_start,
+                                  (u8 *)(&fan_table),
+                                  sizeof(fan_table),
+                                  si_pi->sram_end);
+
+       if (ret) {
+               DRM_ERROR("Failed to load fan table to the SMC.");
+               rdev->pm.dpm.fan.ucode_fan_control = false;
+       }
+
+       return 0;
+}
+
+static int si_fan_ctrl_start_smc_fan_control(struct radeon_device *rdev)
+{
+       PPSMC_Result ret;
+
+       ret = si_send_msg_to_smc(rdev, PPSMC_StartFanControl);
+       if (ret == PPSMC_Result_OK)
+               return 0;
+       else
+               return -EINVAL;
+}
+
+static int si_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev)
+{
+       PPSMC_Result ret;
+
+       ret = si_send_msg_to_smc(rdev, PPSMC_StopFanControl);
+       if (ret == PPSMC_Result_OK)
+               return 0;
+       else
+               return -EINVAL;
+}
+
+#if 0
+static int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
+                                            u32 *speed)
+{
+       u32 duty, duty100;
+       u64 tmp64;
+
+       if (rdev->pm.no_fan)
+               return -ENOENT;
+
+       duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
+       duty = (RREG32(CG_THERMAL_STATUS) & FDO_PWM_DUTY_MASK) >> FDO_PWM_DUTY_SHIFT;
+
+       if (duty100 == 0)
+               return -EINVAL;
+
+       tmp64 = (u64)duty * 100;
+       do_div(tmp64, duty100);
+       *speed = (u32)tmp64;
+
+       if (*speed > 100)
+               *speed = 100;
+
+       return 0;
+}
+
+static int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
+                                            u32 speed)
+{
+       u32 tmp;
+       u32 duty, duty100;
+       u64 tmp64;
+
+       if (rdev->pm.no_fan)
+               return -ENOENT;
+
+       if (speed > 100)
+               return -EINVAL;
+
+       if (rdev->pm.dpm.fan.ucode_fan_control)
+               si_fan_ctrl_stop_smc_fan_control(rdev);
+
+       duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
+
+       if (duty100 == 0)
+               return -EINVAL;
+
+       tmp64 = (u64)speed * duty100;
+       do_div(tmp64, 100);
+       duty = (u32)tmp64;
+
+       tmp = RREG32(CG_FDO_CTRL0) & ~FDO_STATIC_DUTY_MASK;
+       tmp |= FDO_STATIC_DUTY(duty);
+       WREG32(CG_FDO_CTRL0, tmp);
+
+       si_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
+
+       return 0;
+}
+
+static int si_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev,
+                                        u32 *speed)
+{
+       u32 tach_period;
+       u32 xclk = radeon_get_xclk(rdev);
+
+       if (rdev->pm.no_fan)
+               return -ENOENT;
+
+       if (rdev->pm.fan_pulses_per_revolution == 0)
+               return -ENOENT;
+
+       tach_period = (RREG32(CG_TACH_STATUS) & TACH_PERIOD_MASK) >> TACH_PERIOD_SHIFT;
+       if (tach_period == 0)
+               return -ENOENT;
+
+       *speed = 60 * xclk * 10000 / tach_period;
+
+       return 0;
+}
+
+static int si_fan_ctrl_set_fan_speed_rpm(struct radeon_device *rdev,
+                                        u32 speed)
+{
+       u32 tach_period, tmp;
+       u32 xclk = radeon_get_xclk(rdev);
+
+       if (rdev->pm.no_fan)
+               return -ENOENT;
+
+       if (rdev->pm.fan_pulses_per_revolution == 0)
+               return -ENOENT;
+
+       if ((speed < rdev->pm.fan_min_rpm) ||
+           (speed > rdev->pm.fan_max_rpm))
+               return -EINVAL;
+
+       if (rdev->pm.dpm.fan.ucode_fan_control)
+               si_fan_ctrl_stop_smc_fan_control(rdev);
+
+       tach_period = 60 * xclk * 10000 / (8 * speed);
+       tmp = RREG32(CG_TACH_CTRL) & ~TARGET_PERIOD_MASK;
+       tmp |= TARGET_PERIOD(tach_period);
+       WREG32(CG_TACH_CTRL, tmp);
+
+       si_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
+
+       return 0;
+}
+#endif
+
+static void si_fan_ctrl_set_default_mode(struct radeon_device *rdev)
+{
+       struct si_power_info *si_pi = si_get_pi(rdev);
+       u32 tmp;
+
+       if (!si_pi->fan_ctrl_is_in_default_mode) {
+               tmp = RREG32(CG_FDO_CTRL2) & ~FDO_PWM_MODE_MASK;
+               tmp |= FDO_PWM_MODE(si_pi->fan_ctrl_default_mode);
+               WREG32(CG_FDO_CTRL2, tmp);
+
+               tmp = RREG32(CG_FDO_CTRL2) & TMIN_MASK;
+               tmp |= TMIN(si_pi->t_min);
+               WREG32(CG_FDO_CTRL2, tmp);
+               si_pi->fan_ctrl_is_in_default_mode = true;
+       }
+}
+
+static void si_thermal_start_smc_fan_control(struct radeon_device *rdev)
+{
+       if (rdev->pm.dpm.fan.ucode_fan_control) {
+               si_fan_ctrl_start_smc_fan_control(rdev);
+               si_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
+       }
+}
+
+static void si_thermal_initialize(struct radeon_device *rdev)
+{
+       u32 tmp;
+
+       if (rdev->pm.fan_pulses_per_revolution) {
+               tmp = RREG32(CG_TACH_CTRL) & ~EDGE_PER_REV_MASK;
+               tmp |= EDGE_PER_REV(rdev->pm.fan_pulses_per_revolution -1);
+               WREG32(CG_TACH_CTRL, tmp);
+       }
+
+       tmp = RREG32(CG_FDO_CTRL2) & ~TACH_PWM_RESP_RATE_MASK;
+       tmp |= TACH_PWM_RESP_RATE(0x28);
+       WREG32(CG_FDO_CTRL2, tmp);
+}
+
+static int si_thermal_start_thermal_controller(struct radeon_device *rdev)
+{
+       int ret;
+
+       si_thermal_initialize(rdev);
+       ret = si_thermal_set_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+       if (ret)
+               return ret;
+       ret = si_thermal_enable_alert(rdev, true);
+       if (ret)
+               return ret;
+       if (rdev->pm.dpm.fan.ucode_fan_control) {
+               ret = si_halt_smc(rdev);
+               if (ret)
+                       return ret;
+               ret = si_thermal_setup_fan_table(rdev);
+               if (ret)
+                       return ret;
+               ret = si_resume_smc(rdev);
+               if (ret)
+                       return ret;
+               si_thermal_start_smc_fan_control(rdev);
+       }
+
+       return 0;
+}
+
+static void si_thermal_stop_thermal_controller(struct radeon_device *rdev)
+{
+       if (!rdev->pm.no_fan) {
+               si_fan_ctrl_set_default_mode(rdev);
+               si_fan_ctrl_stop_smc_fan_control(rdev);
+       }
+}
+
 int si_dpm_enable(struct radeon_device *rdev)
 {
        struct rv7xx_power_info *pi = rv770_get_pi(rdev);
@@ -5954,31 +6291,39 @@ int si_dpm_enable(struct radeon_device *rdev)
 
        si_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
 
+       si_thermal_start_thermal_controller(rdev);
+
        ni_update_current_ps(rdev, boot_ps);
 
        return 0;
 }
 
-int si_dpm_late_enable(struct radeon_device *rdev)
+static int si_set_temperature_range(struct radeon_device *rdev)
 {
        int ret;
 
-       if (rdev->irq.installed &&
-           r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
-               PPSMC_Result result;
+       ret = si_thermal_enable_alert(rdev, false);
+       if (ret)
+               return ret;
+       ret = si_thermal_set_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+       if (ret)
+               return ret;
+       ret = si_thermal_enable_alert(rdev, true);
+       if (ret)
+               return ret;
 
-               ret = si_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
-               if (ret)
-                       return ret;
-               rdev->irq.dpm_thermal = true;
-               radeon_irq_set(rdev);
-               result = si_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
+       return ret;
+}
 
-               if (result != PPSMC_Result_OK)
-                       DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
-       }
+int si_dpm_late_enable(struct radeon_device *rdev)
+{
+       int ret;
 
-       return 0;
+       ret = si_set_temperature_range(rdev);
+       if (ret)
+               return ret;
+
+       return ret;
 }
 
 void si_dpm_disable(struct radeon_device *rdev)
@@ -5988,6 +6333,7 @@ void si_dpm_disable(struct radeon_device *rdev)
 
        if (!si_is_smc_running(rdev))
                return;
+       si_thermal_stop_thermal_controller(rdev);
        si_disable_ulv(rdev);
        si_clear_vc(rdev);
        if (pi->thermal_protection)
@@ -6526,6 +6872,9 @@ int si_dpm_init(struct radeon_device *rdev)
                rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc =
                        rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
 
+       si_pi->fan_ctrl_is_in_default_mode = true;
+       rdev->pm.dpm.fan.ucode_fan_control = false;
+
        return 0;
 }
 
index 8b5c06a0832df96bfc45f876398529c1f7151c10..d16bb1b5f10f8490b64ed34030848b5732f719e8 100644 (file)
@@ -182,6 +182,7 @@ struct si_power_info {
        u32 dte_table_start;
        u32 spll_table_start;
        u32 papm_cfg_table_start;
+       u32 fan_table_start;
        /* CAC stuff */
        const struct si_cac_config_reg *cac_weights;
        const struct si_cac_config_reg *lcac_config;
@@ -197,6 +198,10 @@ struct si_power_info {
        /* SVI2 */
        u8 svd_gpio_id;
        u8 svc_gpio_id;
+       /* fan control */
+       bool fan_ctrl_is_in_default_mode;
+       u32 t_min;
+       u32 fan_ctrl_default_mode;
 };
 
 #define SISLANDS_INITIAL_STATE_ARB_INDEX    0
index 73dbc79c959d1f8093f035ac0dda87c561728429..e5bb92f16775296e5de6715daac954a78291897a 100644 (file)
@@ -135,7 +135,7 @@ void si_reset_smc(struct radeon_device *rdev)
 
 int si_program_jump_on_start(struct radeon_device *rdev)
 {
-       static u8 data[] = { 0x0E, 0x00, 0x40, 0x40 };
+       static const u8 data[] = { 0x0E, 0x00, 0x40, 0x40 };
 
        return si_copy_bytes_to_smc(rdev, 0x0, data, 4, sizeof(data)+1);
 }
index 6635da9ec986f9b4eadfa50021f4f35cafe25a61..c549c16a4fe48f2f7d28f3d340a9eca43d3a2249 100644 (file)
 #define                DIG_THERM_DPM(x)                        ((x) << 14)
 #define                DIG_THERM_DPM_MASK                      0x003FC000
 #define                DIG_THERM_DPM_SHIFT                     14
-
+#define        CG_THERMAL_STATUS                               0x704
+#define                FDO_PWM_DUTY(x)                         ((x) << 9)
+#define                FDO_PWM_DUTY_MASK                       (0xff << 9)
+#define                FDO_PWM_DUTY_SHIFT                      9
 #define        CG_THERMAL_INT                                  0x708
 #define                DIG_THERM_INTH(x)                       ((x) << 8)
 #define                DIG_THERM_INTH_MASK                     0x0000FF00
 #define        THERM_INT_MASK_HIGH                     (1 << 24)
 #define        THERM_INT_MASK_LOW                      (1 << 25)
 
+#define        CG_MULT_THERMAL_CTRL                                    0x710
+#define                TEMP_SEL(x)                                     ((x) << 20)
+#define                TEMP_SEL_MASK                                   (0xff << 20)
+#define                TEMP_SEL_SHIFT                                  20
 #define        CG_MULT_THERMAL_STATUS                                  0x714
 #define                ASIC_MAX_TEMP(x)                                ((x) << 0)
 #define                ASIC_MAX_TEMP_MASK                              0x000001ff
 #define                CTF_TEMP_MASK                                   0x0003fe00
 #define                CTF_TEMP_SHIFT                                  9
 
+#define        CG_FDO_CTRL0                                    0x754
+#define                FDO_STATIC_DUTY(x)                      ((x) << 0)
+#define                FDO_STATIC_DUTY_MASK                    0x0000000F
+#define                FDO_STATIC_DUTY_SHIFT                   0
+#define        CG_FDO_CTRL1                                    0x758
+#define                FMAX_DUTY100(x)                         ((x) << 0)
+#define                FMAX_DUTY100_MASK                       0x0000000F
+#define                FMAX_DUTY100_SHIFT                      0
+#define        CG_FDO_CTRL2                                    0x75C
+#define                TMIN(x)                                 ((x) << 0)
+#define                TMIN_MASK                               0x0000000F
+#define                TMIN_SHIFT                              0
+#define                FDO_PWM_MODE(x)                         ((x) << 11)
+#define                FDO_PWM_MODE_MASK                       (3 << 11)
+#define                FDO_PWM_MODE_SHIFT                      11
+#define                TACH_PWM_RESP_RATE(x)                   ((x) << 25)
+#define                TACH_PWM_RESP_RATE_MASK                 (0x7f << 25)
+#define                TACH_PWM_RESP_RATE_SHIFT                25
+
+#define CG_TACH_CTRL                                    0x770
+#       define EDGE_PER_REV(x)                          ((x) << 0)
+#       define EDGE_PER_REV_MASK                        (0x7 << 0)
+#       define EDGE_PER_REV_SHIFT                       0
+#       define TARGET_PERIOD(x)                         ((x) << 3)
+#       define TARGET_PERIOD_MASK                       0xfffffff8
+#       define TARGET_PERIOD_SHIFT                      3
+#define CG_TACH_STATUS                                  0x774
+#       define TACH_PERIOD(x)                           ((x) << 0)
+#       define TACH_PERIOD_MASK                         0xffffffff
+#       define TACH_PERIOD_SHIFT                        0
+
 #define GENERAL_PWRMGT                                  0x780
 #       define GLOBAL_PWRMGT_EN                         (1 << 0)
 #       define STATIC_PM_EN                             (1 << 1)
index 623a0b1e2d9dbf017b7af5218996daabc9ec2ab6..3c779838d9ab16ad13a0588b1f69ac323509d933 100644 (file)
@@ -245,6 +245,31 @@ typedef struct SISLANDS_SMC_STATETABLE SISLANDS_SMC_STATETABLE;
 #define SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svd   0x11c
 #define SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svc   0x120
 
+struct PP_SIslands_FanTable
+{
+       uint8_t  fdo_mode;
+       uint8_t  padding;
+       int16_t  temp_min;
+       int16_t  temp_med;
+       int16_t  temp_max;
+       int16_t  slope1;
+       int16_t  slope2;
+       int16_t  fdo_min;
+       int16_t  hys_up;
+       int16_t  hys_down;
+       int16_t  hys_slope;
+       int16_t  temp_resp_lim;
+       int16_t  temp_curr;
+       int16_t  slope_curr;
+       int16_t  pwm_curr;
+       uint32_t refresh_period;
+       int16_t  fdo_max;
+       uint8_t  temp_src;
+       int8_t  padding2;
+};
+
+typedef struct PP_SIslands_FanTable PP_SIslands_FanTable;
+
 #define SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16
 #define SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES 32
 
index 82f70c90a9ee9623991fd538bafbaddb5cc1a53c..0b0b404ff0916a9e72f241400c113b63b43d4a0f 100644 (file)
@@ -431,6 +431,31 @@ struct SMU7_Discrete_MCRegisters
 
 typedef struct SMU7_Discrete_MCRegisters SMU7_Discrete_MCRegisters;
 
+struct SMU7_Discrete_FanTable
+{
+       uint16_t FdoMode;
+       int16_t  TempMin;
+       int16_t  TempMed;
+       int16_t  TempMax;
+       int16_t  Slope1;
+       int16_t  Slope2;
+       int16_t  FdoMin;
+       int16_t  HystUp;
+       int16_t  HystDown;
+       int16_t  HystSlope;
+       int16_t  TempRespLim;
+       int16_t  TempCurr;
+       int16_t  SlopeCurr;
+       int16_t  PwmCurr;
+       uint32_t RefreshPeriod;
+       int16_t  FdoMax;
+       uint8_t  TempSrc;
+       int8_t   Padding;
+};
+
+typedef struct SMU7_Discrete_FanTable SMU7_Discrete_FanTable;
+
+
 struct SMU7_Discrete_PmFuses {
   // dw0-dw1
   uint8_t BapmVddCVidHiSidd[8];
@@ -462,7 +487,10 @@ struct SMU7_Discrete_PmFuses {
   uint8_t BapmVddCVidHiSidd2[8];
 
   // dw11-dw12
-  uint32_t Reserved6[2];
+  int16_t FuzzyFan_ErrorSetDelta;
+  int16_t FuzzyFan_ErrorRateSetDelta;
+  int16_t FuzzyFan_PwmSetDelta;
+  uint16_t CalcMeasPowerBlend;
 
   // dw13-dw16
   uint8_t GnbLPML[16];
index c96f6089f8bf195377a933a8b1632565ebe49930..2324a526de6516ecbde0b77fe6490ef4b63e0b36 100644 (file)
@@ -11,10 +11,17 @@ config DRM_RCAR_DU
          Choose this option if you have an R-Car chipset.
          If M is selected the module will be called rcar-du-drm.
 
+config DRM_RCAR_HDMI
+       bool "R-Car DU HDMI Encoder Support"
+       depends on DRM_RCAR_DU
+       depends on OF
+       help
+         Enable support for external HDMI encoders.
+
 config DRM_RCAR_LVDS
        bool "R-Car DU LVDS Encoder Support"
        depends on DRM_RCAR_DU
        depends on ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST
        help
-         Enable support the R-Car Display Unit embedded LVDS encoders
-         (currently only on R8A7790).
+         Enable support for the R-Car Display Unit embedded LVDS encoders
+         (currently only on R8A7790 and R8A7791).
index 12b8d447783538518e491d34cfca1fc87a9a3683..05de1c4097af92192bbb28ee5c7a704775a9b1db 100644 (file)
@@ -7,6 +7,8 @@ rcar-du-drm-y := rcar_du_crtc.o \
                 rcar_du_plane.o \
                 rcar_du_vgacon.o
 
+rcar-du-drm-$(CONFIG_DRM_RCAR_HDMI)    += rcar_du_hdmicon.o \
+                                          rcar_du_hdmienc.o
 rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)    += rcar_du_lvdsenc.o
 
 obj-$(CONFIG_DRM_RCAR_DU)              += rcar-du-drm.o
index 088bfd875d297bcc01fcff558616d5f86399a3db..23cc910951f430a279b6b01ae88e5f03d7de3e74 100644 (file)
@@ -586,7 +586,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
 
        if (irq < 0) {
                dev_err(rcdu->dev, "no IRQ for CRTC %u\n", index);
-               return ret;
+               return irq;
        }
 
        ret = devm_request_irq(rcdu->dev, irq, rcar_du_crtc_irq, irqflags,
index e97ae502dec5ffaa50311d84f96d66b17e69ea8b..984e6083699fe380a1d6b1e9d9c4c249ee6d4167 100644 (file)
@@ -15,7 +15,6 @@
 #define __RCAR_DU_CRTC_H__
 
 #include <linux/mutex.h>
-#include <linux/platform_data/rcar-du.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
@@ -41,6 +40,15 @@ struct rcar_du_crtc {
 
 #define to_rcar_crtc(c)        container_of(c, struct rcar_du_crtc, crtc)
 
+enum rcar_du_output {
+       RCAR_DU_OUTPUT_DPAD0,
+       RCAR_DU_OUTPUT_DPAD1,
+       RCAR_DU_OUTPUT_LVDS0,
+       RCAR_DU_OUTPUT_LVDS1,
+       RCAR_DU_OUTPUT_TCON,
+       RCAR_DU_OUTPUT_MAX,
+};
+
 int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index);
 void rcar_du_crtc_enable_vblank(struct rcar_du_crtc *rcrtc, bool enable);
 void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc,
index d212efa6a49510db6b51f60a77357e5b6c5e09a9..967ae8f20233ed163540ff9117fb7a3daae2750a 100644 (file)
@@ -146,12 +146,11 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags)
 {
        struct platform_device *pdev = dev->platformdev;
        struct device_node *np = pdev->dev.of_node;
-       struct rcar_du_platform_data *pdata = pdev->dev.platform_data;
        struct rcar_du_device *rcdu;
        struct resource *mem;
        int ret;
 
-       if (pdata == NULL && np == NULL) {
+       if (np == NULL) {
                dev_err(dev->dev, "no platform data\n");
                return -ENODEV;
        }
@@ -163,7 +162,6 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags)
        }
 
        rcdu->dev = &pdev->dev;
-       rcdu->pdata = pdata;
        rcdu->info = np ? of_match_device(rcar_du_of_table, rcdu->dev)->data
                   : (void *)platform_get_device_id(pdev)->driver_data;
        rcdu->ddev = dev;
index 8e494633c3b36325b99833dfd7ed294cab975962..0a724669f02d461351617c5044b4e7e89f7262da 100644 (file)
@@ -15,7 +15,6 @@
 #define __RCAR_DU_DRV_H__
 
 #include <linux/kernel.h>
-#include <linux/platform_data/rcar-du.h>
 
 #include "rcar_du_crtc.h"
 #include "rcar_du_group.h"
@@ -67,7 +66,6 @@ struct rcar_du_device_info {
 
 struct rcar_du_device {
        struct device *dev;
-       const struct rcar_du_platform_data *pdata;
        const struct rcar_du_device_info *info;
 
        void __iomem *mmio;
index 7c0ec95915eff1b1a46fb0319f5ae7eea353c26a..34a122a3966419e406cb958ce8a6b194f9fdae1f 100644 (file)
@@ -19,6 +19,8 @@
 
 #include "rcar_du_drv.h"
 #include "rcar_du_encoder.h"
+#include "rcar_du_hdmicon.h"
+#include "rcar_du_hdmienc.h"
 #include "rcar_du_kms.h"
 #include "rcar_du_lvdscon.h"
 #include "rcar_du_lvdsenc.h"
@@ -33,7 +35,7 @@ rcar_du_connector_best_encoder(struct drm_connector *connector)
 {
        struct rcar_du_connector *rcon = to_rcar_connector(connector);
 
-       return &rcon->encoder->encoder;
+       return rcar_encoder_to_drm_encoder(rcon->encoder);
 }
 
 /* -----------------------------------------------------------------------------
@@ -142,10 +144,11 @@ static const struct drm_encoder_funcs encoder_funcs = {
 int rcar_du_encoder_init(struct rcar_du_device *rcdu,
                         enum rcar_du_encoder_type type,
                         enum rcar_du_output output,
-                        const struct rcar_du_encoder_data *data,
-                        struct device_node *np)
+                        struct device_node *enc_node,
+                        struct device_node *con_node)
 {
        struct rcar_du_encoder *renc;
+       struct drm_encoder *encoder;
        unsigned int encoder_type;
        int ret;
 
@@ -154,6 +157,7 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
                return -ENOMEM;
 
        renc->output = output;
+       encoder = rcar_encoder_to_drm_encoder(renc);
 
        switch (output) {
        case RCAR_DU_OUTPUT_LVDS0:
@@ -175,6 +179,9 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
        case RCAR_DU_ENCODER_LVDS:
                encoder_type = DRM_MODE_ENCODER_LVDS;
                break;
+       case RCAR_DU_ENCODER_HDMI:
+               encoder_type = DRM_MODE_ENCODER_TMDS;
+               break;
        case RCAR_DU_ENCODER_NONE:
        default:
                /* No external encoder, use the internal encoder type. */
@@ -182,23 +189,35 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
                break;
        }
 
-       ret = drm_encoder_init(rcdu->ddev, &renc->encoder, &encoder_funcs,
-                              encoder_type);
-       if (ret < 0)
-               return ret;
+       if (type == RCAR_DU_ENCODER_HDMI) {
+               if (renc->lvds) {
+                       dev_err(rcdu->dev,
+                               "Chaining LVDS and HDMI encoders not supported\n");
+                       return -EINVAL;
+               }
 
-       drm_encoder_helper_add(&renc->encoder, &encoder_helper_funcs);
+               ret = rcar_du_hdmienc_init(rcdu, renc, enc_node);
+               if (ret < 0)
+                       return ret;
+       } else {
+               ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
+                                      encoder_type);
+               if (ret < 0)
+                       return ret;
 
-       switch (encoder_type) {
-       case DRM_MODE_ENCODER_LVDS: {
-               const struct rcar_du_panel_data *pdata =
-                       data ? &data->connector.lvds.panel : NULL;
-               return rcar_du_lvds_connector_init(rcdu, renc, pdata, np);
+               drm_encoder_helper_add(encoder, &encoder_helper_funcs);
        }
 
+       switch (encoder_type) {
+       case DRM_MODE_ENCODER_LVDS:
+               return rcar_du_lvds_connector_init(rcdu, renc, con_node);
+
        case DRM_MODE_ENCODER_DAC:
                return rcar_du_vga_connector_init(rcdu, renc);
 
+       case DRM_MODE_ENCODER_TMDS:
+               return rcar_du_hdmi_connector_init(rcdu, renc);
+
        default:
                return -EINVAL;
        }
index bd624135ef1fbfed3257bc4377b1e17a441b2021..719b6f2a031ccf0756ebd718307196b23d3f22b6 100644 (file)
 #ifndef __RCAR_DU_ENCODER_H__
 #define __RCAR_DU_ENCODER_H__
 
-#include <linux/platform_data/rcar-du.h>
-
 #include <drm/drm_crtc.h>
+#include <drm/drm_encoder_slave.h>
 
 struct rcar_du_device;
+struct rcar_du_hdmienc;
 struct rcar_du_lvdsenc;
 
+enum rcar_du_encoder_type {
+       RCAR_DU_ENCODER_UNUSED = 0,
+       RCAR_DU_ENCODER_NONE,
+       RCAR_DU_ENCODER_VGA,
+       RCAR_DU_ENCODER_LVDS,
+       RCAR_DU_ENCODER_HDMI,
+};
+
 struct rcar_du_encoder {
-       struct drm_encoder encoder;
+       struct drm_encoder_slave slave;
        enum rcar_du_output output;
+       struct rcar_du_hdmienc *hdmi;
        struct rcar_du_lvdsenc *lvds;
 };
 
 #define to_rcar_encoder(e) \
-       container_of(e, struct rcar_du_encoder, encoder)
+       container_of(e, struct rcar_du_encoder, slave.base)
+
+#define rcar_encoder_to_drm_encoder(e) (&(e)->slave.base)
 
 struct rcar_du_connector {
        struct drm_connector connector;
@@ -44,7 +55,7 @@ rcar_du_connector_best_encoder(struct drm_connector *connector);
 int rcar_du_encoder_init(struct rcar_du_device *rcdu,
                         enum rcar_du_encoder_type type,
                         enum rcar_du_output output,
-                        const struct rcar_du_encoder_data *data,
-                        struct device_node *np);
+                        struct device_node *enc_node,
+                        struct device_node *con_node);
 
 #endif /* __RCAR_DU_ENCODER_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
new file mode 100644 (file)
index 0000000..8abaaf2
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * R-Car Display Unit HDMI Connector
+ *
+ * Copyright (C) 2014 Renesas Electronics Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.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 <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_encoder_slave.h>
+
+#include "rcar_du_drv.h"
+#include "rcar_du_encoder.h"
+#include "rcar_du_hdmicon.h"
+#include "rcar_du_kms.h"
+
+#define to_slave_funcs(e)      (to_rcar_encoder(e)->slave.slave_funcs)
+
+static int rcar_du_hdmi_connector_get_modes(struct drm_connector *connector)
+{
+       struct drm_encoder *encoder = connector->encoder;
+       struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+
+       if (sfuncs->get_modes == NULL)
+               return 0;
+
+       return sfuncs->get_modes(encoder, connector);
+}
+
+static int rcar_du_hdmi_connector_mode_valid(struct drm_connector *connector,
+                                            struct drm_display_mode *mode)
+{
+       struct drm_encoder *encoder = connector->encoder;
+       struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+
+       if (sfuncs->mode_valid == NULL)
+               return MODE_OK;
+
+       return sfuncs->mode_valid(encoder, mode);
+}
+
+static const struct drm_connector_helper_funcs connector_helper_funcs = {
+       .get_modes = rcar_du_hdmi_connector_get_modes,
+       .mode_valid = rcar_du_hdmi_connector_mode_valid,
+       .best_encoder = rcar_du_connector_best_encoder,
+};
+
+static void rcar_du_hdmi_connector_destroy(struct drm_connector *connector)
+{
+       drm_connector_unregister(connector);
+       drm_connector_cleanup(connector);
+}
+
+static enum drm_connector_status
+rcar_du_hdmi_connector_detect(struct drm_connector *connector, bool force)
+{
+       struct drm_encoder *encoder = connector->encoder;
+       struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+
+       if (sfuncs->detect == NULL)
+               return connector_status_unknown;
+
+       return sfuncs->detect(encoder, connector);
+}
+
+static const struct drm_connector_funcs connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = rcar_du_hdmi_connector_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = rcar_du_hdmi_connector_destroy,
+};
+
+int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
+                               struct rcar_du_encoder *renc)
+{
+       struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc);
+       struct rcar_du_connector *rcon;
+       struct drm_connector *connector;
+       int ret;
+
+       rcon = devm_kzalloc(rcdu->dev, sizeof(*rcon), GFP_KERNEL);
+       if (rcon == NULL)
+               return -ENOMEM;
+
+       connector = &rcon->connector;
+       connector->display_info.width_mm = 0;
+       connector->display_info.height_mm = 0;
+
+       ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
+                                DRM_MODE_CONNECTOR_HDMIA);
+       if (ret < 0)
+               return ret;
+
+       drm_connector_helper_add(connector, &connector_helper_funcs);
+       ret = drm_connector_register(connector);
+       if (ret < 0)
+               return ret;
+
+       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+       drm_object_property_set_value(&connector->base,
+               rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
+
+       ret = drm_mode_connector_attach_encoder(connector, encoder);
+       if (ret < 0)
+               return ret;
+
+       connector->encoder = encoder;
+       rcon->encoder = renc;
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.h b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.h
new file mode 100644 (file)
index 0000000..87daa94
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * R-Car Display Unit HDMI Connector
+ *
+ * Copyright (C) 2014 Renesas Electronics Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.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.
+ */
+
+#ifndef __RCAR_DU_HDMICON_H__
+#define __RCAR_DU_HDMICON_H__
+
+struct rcar_du_device;
+struct rcar_du_encoder;
+
+#if IS_ENABLED(CONFIG_DRM_RCAR_HDMI)
+int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
+                               struct rcar_du_encoder *renc);
+#else
+static inline int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
+                                             struct rcar_du_encoder *renc)
+{
+       return -ENOSYS;
+}
+#endif
+
+#endif /* __RCAR_DU_HDMICON_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
new file mode 100644 (file)
index 0000000..359bc99
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * R-Car Display Unit HDMI Encoder
+ *
+ * Copyright (C) 2014 Renesas Electronics Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.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/slab.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_encoder_slave.h>
+
+#include "rcar_du_drv.h"
+#include "rcar_du_encoder.h"
+#include "rcar_du_hdmienc.h"
+
+struct rcar_du_hdmienc {
+       struct rcar_du_encoder *renc;
+       struct device *dev;
+       int dpms;
+};
+
+#define to_rcar_hdmienc(e)     (to_rcar_encoder(e)->hdmi)
+#define to_slave_funcs(e)      (to_rcar_encoder(e)->slave.slave_funcs)
+
+static void rcar_du_hdmienc_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
+       struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+
+       if (hdmienc->dpms == mode)
+               return;
+
+       if (sfuncs->dpms)
+               sfuncs->dpms(encoder, mode);
+
+       hdmienc->dpms = mode;
+}
+
+static bool rcar_du_hdmienc_mode_fixup(struct drm_encoder *encoder,
+                                      const struct drm_display_mode *mode,
+                                      struct drm_display_mode *adjusted_mode)
+{
+       struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+
+       if (sfuncs->mode_fixup == NULL)
+               return true;
+
+       return sfuncs->mode_fixup(encoder, mode, adjusted_mode);
+}
+
+static void rcar_du_hdmienc_mode_prepare(struct drm_encoder *encoder)
+{
+       rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void rcar_du_hdmienc_mode_commit(struct drm_encoder *encoder)
+{
+       rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_ON);
+}
+
+static void rcar_du_hdmienc_mode_set(struct drm_encoder *encoder,
+                                    struct drm_display_mode *mode,
+                                    struct drm_display_mode *adjusted_mode)
+{
+       struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
+       struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+
+       if (sfuncs->mode_set)
+               sfuncs->mode_set(encoder, mode, adjusted_mode);
+
+       rcar_du_crtc_route_output(encoder->crtc, hdmienc->renc->output);
+}
+
+static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
+       .dpms = rcar_du_hdmienc_dpms,
+       .mode_fixup = rcar_du_hdmienc_mode_fixup,
+       .prepare = rcar_du_hdmienc_mode_prepare,
+       .commit = rcar_du_hdmienc_mode_commit,
+       .mode_set = rcar_du_hdmienc_mode_set,
+};
+
+static void rcar_du_hdmienc_cleanup(struct drm_encoder *encoder)
+{
+       struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
+
+       rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_OFF);
+
+       drm_encoder_cleanup(encoder);
+       put_device(hdmienc->dev);
+}
+
+static const struct drm_encoder_funcs encoder_funcs = {
+       .destroy = rcar_du_hdmienc_cleanup,
+};
+
+int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
+                        struct rcar_du_encoder *renc, struct device_node *np)
+{
+       struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc);
+       struct drm_i2c_encoder_driver *driver;
+       struct i2c_client *i2c_slave;
+       struct rcar_du_hdmienc *hdmienc;
+       int ret;
+
+       hdmienc = devm_kzalloc(rcdu->dev, sizeof(*hdmienc), GFP_KERNEL);
+       if (hdmienc == NULL)
+               return -ENOMEM;
+
+       /* Locate the slave I2C device and driver. */
+       i2c_slave = of_find_i2c_device_by_node(np);
+       if (!i2c_slave || !i2c_get_clientdata(i2c_slave))
+               return -EPROBE_DEFER;
+
+       hdmienc->dev = &i2c_slave->dev;
+
+       if (hdmienc->dev->driver == NULL) {
+               ret = -EPROBE_DEFER;
+               goto error;
+       }
+
+       /* Initialize the slave encoder. */
+       driver = to_drm_i2c_encoder_driver(to_i2c_driver(hdmienc->dev->driver));
+       ret = driver->encoder_init(i2c_slave, rcdu->ddev, &renc->slave);
+       if (ret < 0)
+               goto error;
+
+       ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
+                              DRM_MODE_ENCODER_TMDS);
+       if (ret < 0)
+               goto error;
+
+       drm_encoder_helper_add(encoder, &encoder_helper_funcs);
+
+       renc->hdmi = hdmienc;
+       hdmienc->renc = renc;
+
+       return 0;
+
+error:
+       put_device(hdmienc->dev);
+       return ret;
+}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.h b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.h
new file mode 100644 (file)
index 0000000..2ff0128
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * R-Car Display Unit HDMI Encoder
+ *
+ * Copyright (C) 2014 Renesas Electronics Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.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.
+ */
+
+#ifndef __RCAR_DU_HDMIENC_H__
+#define __RCAR_DU_HDMIENC_H__
+
+#include <linux/module.h>
+
+struct device_node;
+struct rcar_du_device;
+struct rcar_du_encoder;
+
+#if IS_ENABLED(CONFIG_DRM_RCAR_HDMI)
+int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
+                        struct rcar_du_encoder *renc, struct device_node *np);
+#else
+static inline int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
+                                      struct rcar_du_encoder *renc,
+                                      struct device_node *np)
+{
+       return -ENOSYS;
+}
+#endif
+
+#endif /* __RCAR_DU_HDMIENC_H__ */
index 6c24ad7d03ef300077cc992b9d3b95fccec2cac1..0c5ee616b5a3aabd12234ee7f208dc277a99d73f 100644 (file)
@@ -126,9 +126,9 @@ int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev,
        else
                align = 16 * args->bpp / 8;
 
-       args->pitch = roundup(max(args->pitch, min_pitch), align);
+       args->pitch = roundup(min_pitch, align);
 
-       return drm_gem_cma_dumb_create(file, dev, args);
+       return drm_gem_cma_dumb_create_internal(file, dev, args);
 }
 
 static struct drm_framebuffer *
@@ -190,49 +190,16 @@ static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = {
        .output_poll_changed = rcar_du_output_poll_changed,
 };
 
-static int rcar_du_encoders_init_pdata(struct rcar_du_device *rcdu)
-{
-       unsigned int num_encoders = 0;
-       unsigned int i;
-       int ret;
-
-       for (i = 0; i < rcdu->pdata->num_encoders; ++i) {
-               const struct rcar_du_encoder_data *pdata =
-                       &rcdu->pdata->encoders[i];
-               const struct rcar_du_output_routing *route =
-                       &rcdu->info->routes[pdata->output];
-
-               if (pdata->type == RCAR_DU_ENCODER_UNUSED)
-                       continue;
-
-               if (pdata->output >= RCAR_DU_OUTPUT_MAX ||
-                   route->possible_crtcs == 0) {
-                       dev_warn(rcdu->dev,
-                                "encoder %u references unexisting output %u, skipping\n",
-                                i, pdata->output);
-                       continue;
-               }
-
-               ret = rcar_du_encoder_init(rcdu, pdata->type, pdata->output,
-                                          pdata, NULL);
-               if (ret < 0)
-                       return ret;
-
-               num_encoders++;
-       }
-
-       return num_encoders;
-}
-
-static int rcar_du_encoders_init_dt_one(struct rcar_du_device *rcdu,
-                                       enum rcar_du_output output,
-                                       struct of_endpoint *ep)
+static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
+                                    enum rcar_du_output output,
+                                    struct of_endpoint *ep)
 {
        static const struct {
                const char *compatible;
                enum rcar_du_encoder_type type;
        } encoders[] = {
                { "adi,adv7123", RCAR_DU_ENCODER_VGA },
+               { "adi,adv7511w", RCAR_DU_ENCODER_HDMI },
                { "thine,thc63lvdm83d", RCAR_DU_ENCODER_LVDS },
        };
 
@@ -323,14 +290,14 @@ static int rcar_du_encoders_init_dt_one(struct rcar_du_device *rcdu,
                connector = entity;
        }
 
-       ret = rcar_du_encoder_init(rcdu, enc_type, output, NULL, connector);
+       ret = rcar_du_encoder_init(rcdu, enc_type, output, encoder, connector);
        of_node_put(encoder);
        of_node_put(connector);
 
        return ret < 0 ? ret : 1;
 }
 
-static int rcar_du_encoders_init_dt(struct rcar_du_device *rcdu)
+static int rcar_du_encoders_init(struct rcar_du_device *rcdu)
 {
        struct device_node *np = rcdu->dev->of_node;
        struct device_node *prev = NULL;
@@ -377,7 +344,7 @@ static int rcar_du_encoders_init_dt(struct rcar_du_device *rcdu)
                }
 
                /* Process the output pipeline. */
-               ret = rcar_du_encoders_init_dt_one(rcdu, output, &ep);
+               ret = rcar_du_encoders_init_one(rcdu, output, &ep);
                if (ret < 0) {
                        of_node_put(ep_node);
                        return ret;
@@ -442,11 +409,7 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
        if (ret < 0)
                return ret;
 
-       if (rcdu->pdata)
-               ret = rcar_du_encoders_init_pdata(rcdu);
-       else
-               ret = rcar_du_encoders_init_dt(rcdu);
-
+       ret = rcar_du_encoders_init(rcdu);
        if (ret < 0)
                return ret;
 
index 115eed20db12abc421eddf7a20db0707c291c4a5..6d9811c052c4bce4d41ea61232fd99aaa71d6aa9 100644 (file)
 struct rcar_du_lvds_connector {
        struct rcar_du_connector connector;
 
-       struct rcar_du_panel_data panel;
+       struct {
+               unsigned int width_mm;          /* Panel width in mm */
+               unsigned int height_mm;         /* Panel height in mm */
+               struct videomode mode;
+       } panel;
 };
 
 #define to_rcar_lvds_connector(c) \
@@ -78,31 +82,26 @@ static const struct drm_connector_funcs connector_funcs = {
 
 int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
                                struct rcar_du_encoder *renc,
-                               const struct rcar_du_panel_data *panel,
                                /* TODO const */ struct device_node *np)
 {
+       struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc);
        struct rcar_du_lvds_connector *lvdscon;
        struct drm_connector *connector;
+       struct display_timing timing;
        int ret;
 
        lvdscon = devm_kzalloc(rcdu->dev, sizeof(*lvdscon), GFP_KERNEL);
        if (lvdscon == NULL)
                return -ENOMEM;
 
-       if (panel) {
-               lvdscon->panel = *panel;
-       } else {
-               struct display_timing timing;
-
-               ret = of_get_display_timing(np, "panel-timing", &timing);
-               if (ret < 0)
-                       return ret;
+       ret = of_get_display_timing(np, "panel-timing", &timing);
+       if (ret < 0)
+               return ret;
 
-               videomode_from_timing(&timing, &lvdscon->panel.mode);
+       videomode_from_timing(&timing, &lvdscon->panel.mode);
 
-               of_property_read_u32(np, "width-mm", &lvdscon->panel.width_mm);
-               of_property_read_u32(np, "height-mm", &lvdscon->panel.height_mm);
-       }
+       of_property_read_u32(np, "width-mm", &lvdscon->panel.width_mm);
+       of_property_read_u32(np, "height-mm", &lvdscon->panel.height_mm);
 
        connector = &lvdscon->connector.connector;
        connector->display_info.width_mm = lvdscon->panel.width_mm;
@@ -122,11 +121,11 @@ int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
        drm_object_property_set_value(&connector->base,
                rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
 
-       ret = drm_mode_connector_attach_encoder(connector, &renc->encoder);
+       ret = drm_mode_connector_attach_encoder(connector, encoder);
        if (ret < 0)
                return ret;
 
-       connector->encoder = &renc->encoder;
+       connector->encoder = encoder;
        lvdscon->connector.encoder = renc;
 
        return 0;
index d11424d537f90334fe30e9dd7ddd8faf430d9790..d4881ee0be7e8aa4df09f5469717592ec0e8c627 100644 (file)
 
 struct rcar_du_device;
 struct rcar_du_encoder;
-struct rcar_du_panel_data;
 
 int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
                                struct rcar_du_encoder *renc,
-                               const struct rcar_du_panel_data *panel,
                                struct device_node *np);
 
 #endif /* __RCAR_DU_LVDSCON_H__ */
index 3303a55cec79dcfb28b4dff7e53d6ac5e4c1fb2b..f65aabda0796bbc62aa9af0326d2dccafd187067 100644 (file)
@@ -16,7 +16,6 @@
 
 #include <linux/io.h>
 #include <linux/module.h>
-#include <linux/platform_data/rcar-du.h>
 
 struct rcar_drm_crtc;
 struct rcar_du_lvdsenc;
index 564a723ede0374e5def036e085b009bef4b1a954..752747a5e920e847ac689aa78555da1c12716b9e 100644 (file)
@@ -52,6 +52,7 @@ static const struct drm_connector_funcs connector_funcs = {
 int rcar_du_vga_connector_init(struct rcar_du_device *rcdu,
                               struct rcar_du_encoder *renc)
 {
+       struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc);
        struct rcar_du_connector *rcon;
        struct drm_connector *connector;
        int ret;
@@ -78,11 +79,11 @@ int rcar_du_vga_connector_init(struct rcar_du_device *rcdu,
        drm_object_property_set_value(&connector->base,
                rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
 
-       ret = drm_mode_connector_attach_encoder(connector, &renc->encoder);
+       ret = drm_mode_connector_attach_encoder(connector, encoder);
        if (ret < 0)
                return ret;
 
-       connector->encoder = &renc->encoder;
+       connector->encoder = encoder;
        rcon->encoder = renc;
 
        return 0;
index 354ddb29231f26e67e6ac9ec3a638358b47923c4..74d9d621453da3f341227933840fb0cfe41f906e 100644 (file)
@@ -1,6 +1,7 @@
 config DRM_TEGRA
        tristate "NVIDIA Tegra DRM"
        depends on ARCH_TEGRA || (ARM && COMPILE_TEST)
+       depends on COMMON_CLK
        depends on DRM
        depends on RESET_CONTROLLER
        select DRM_KMS_HELPER
index 13bea1bbb881f34d2ec5121880a8e6e7e470fb9d..3367960286a6f162455e0363a54dace2c6882883 100644 (file)
@@ -9,8 +9,11 @@
 
 #include <linux/clk.h>
 #include <linux/debugfs.h>
+#include <linux/iommu.h>
 #include <linux/reset.h>
 
+#include <soc/tegra/pmc.h>
+
 #include "dc.h"
 #include "drm.h"
 #include "gem.h"
@@ -22,6 +25,7 @@ struct tegra_dc_soc_info {
        bool supports_cursor;
        bool supports_block_linear;
        unsigned int pitch_align;
+       bool has_powergate;
 };
 
 struct tegra_plane {
@@ -34,6 +38,26 @@ static inline struct tegra_plane *to_tegra_plane(struct drm_plane *plane)
        return container_of(plane, struct tegra_plane, base);
 }
 
+static void tegra_dc_window_commit(struct tegra_dc *dc, unsigned int index)
+{
+       u32 value = WIN_A_ACT_REQ << index;
+
+       tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL);
+       tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
+}
+
+static void tegra_dc_cursor_commit(struct tegra_dc *dc)
+{
+       tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
+       tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);
+}
+
+static void tegra_dc_commit(struct tegra_dc *dc)
+{
+       tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
+       tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+}
+
 static unsigned int tegra_dc_format(uint32_t format, uint32_t *swap)
 {
        /* assume no swapping of fetched data */
@@ -305,17 +329,260 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
                break;
        }
 
-       tegra_dc_writel(dc, WIN_A_UPDATE << index, DC_CMD_STATE_CONTROL);
-       tegra_dc_writel(dc, WIN_A_ACT_REQ << index, DC_CMD_STATE_CONTROL);
+       tegra_dc_window_commit(dc, index);
+
+       return 0;
+}
+
+static int tegra_window_plane_disable(struct drm_plane *plane)
+{
+       struct tegra_dc *dc = to_tegra_dc(plane->crtc);
+       struct tegra_plane *p = to_tegra_plane(plane);
+       u32 value;
+
+       if (!plane->crtc)
+               return 0;
+
+       value = WINDOW_A_SELECT << p->index;
+       tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
+
+       value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
+       value &= ~WIN_ENABLE;
+       tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
+
+       tegra_dc_window_commit(dc, p->index);
+
+       return 0;
+}
+
+static void tegra_plane_destroy(struct drm_plane *plane)
+{
+       struct tegra_plane *p = to_tegra_plane(plane);
+
+       drm_plane_cleanup(plane);
+       kfree(p);
+}
+
+static const u32 tegra_primary_plane_formats[] = {
+       DRM_FORMAT_XBGR8888,
+       DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_RGB565,
+};
+
+static int tegra_primary_plane_update(struct drm_plane *plane,
+                                     struct drm_crtc *crtc,
+                                     struct drm_framebuffer *fb, int crtc_x,
+                                     int crtc_y, unsigned int crtc_w,
+                                     unsigned int crtc_h, uint32_t src_x,
+                                     uint32_t src_y, uint32_t src_w,
+                                     uint32_t src_h)
+{
+       struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
+       struct tegra_plane *p = to_tegra_plane(plane);
+       struct tegra_dc *dc = to_tegra_dc(crtc);
+       struct tegra_dc_window window;
+       int err;
+
+       memset(&window, 0, sizeof(window));
+       window.src.x = src_x >> 16;
+       window.src.y = src_y >> 16;
+       window.src.w = src_w >> 16;
+       window.src.h = src_h >> 16;
+       window.dst.x = crtc_x;
+       window.dst.y = crtc_y;
+       window.dst.w = crtc_w;
+       window.dst.h = crtc_h;
+       window.format = tegra_dc_format(fb->pixel_format, &window.swap);
+       window.bits_per_pixel = fb->bits_per_pixel;
+       window.bottom_up = tegra_fb_is_bottom_up(fb);
+
+       err = tegra_fb_get_tiling(fb, &window.tiling);
+       if (err < 0)
+               return err;
+
+       window.base[0] = bo->paddr + fb->offsets[0];
+       window.stride[0] = fb->pitches[0];
+
+       err = tegra_dc_setup_window(dc, p->index, &window);
+       if (err < 0)
+               return err;
 
        return 0;
 }
 
-static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
-                             struct drm_framebuffer *fb, int crtc_x,
-                             int crtc_y, unsigned int crtc_w,
-                             unsigned int crtc_h, uint32_t src_x,
-                             uint32_t src_y, uint32_t src_w, uint32_t src_h)
+static void tegra_primary_plane_destroy(struct drm_plane *plane)
+{
+       tegra_window_plane_disable(plane);
+       tegra_plane_destroy(plane);
+}
+
+static const struct drm_plane_funcs tegra_primary_plane_funcs = {
+       .update_plane = tegra_primary_plane_update,
+       .disable_plane = tegra_window_plane_disable,
+       .destroy = tegra_primary_plane_destroy,
+};
+
+static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm,
+                                                      struct tegra_dc *dc)
+{
+       struct tegra_plane *plane;
+       unsigned int num_formats;
+       const u32 *formats;
+       int err;
+
+       plane = kzalloc(sizeof(*plane), GFP_KERNEL);
+       if (!plane)
+               return ERR_PTR(-ENOMEM);
+
+       num_formats = ARRAY_SIZE(tegra_primary_plane_formats);
+       formats = tegra_primary_plane_formats;
+
+       err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
+                                      &tegra_primary_plane_funcs, formats,
+                                      num_formats, DRM_PLANE_TYPE_PRIMARY);
+       if (err < 0) {
+               kfree(plane);
+               return ERR_PTR(err);
+       }
+
+       return &plane->base;
+}
+
+static const u32 tegra_cursor_plane_formats[] = {
+       DRM_FORMAT_RGBA8888,
+};
+
+static int tegra_cursor_plane_update(struct drm_plane *plane,
+                                    struct drm_crtc *crtc,
+                                    struct drm_framebuffer *fb, int crtc_x,
+                                    int crtc_y, unsigned int crtc_w,
+                                    unsigned int crtc_h, uint32_t src_x,
+                                    uint32_t src_y, uint32_t src_w,
+                                    uint32_t src_h)
+{
+       struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
+       struct tegra_dc *dc = to_tegra_dc(crtc);
+       u32 value = CURSOR_CLIP_DISPLAY;
+
+       /* scaling not supported for cursor */
+       if ((src_w >> 16 != crtc_w) || (src_h >> 16 != crtc_h))
+               return -EINVAL;
+
+       /* only square cursors supported */
+       if (src_w != src_h)
+               return -EINVAL;
+
+       switch (crtc_w) {
+       case 32:
+               value |= CURSOR_SIZE_32x32;
+               break;
+
+       case 64:
+               value |= CURSOR_SIZE_64x64;
+               break;
+
+       case 128:
+               value |= CURSOR_SIZE_128x128;
+               break;
+
+       case 256:
+               value |= CURSOR_SIZE_256x256;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       value |= (bo->paddr >> 10) & 0x3fffff;
+       tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR);
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+       value = (bo->paddr >> 32) & 0x3;
+       tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR_HI);
+#endif
+
+       /* enable cursor and set blend mode */
+       value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+       value |= CURSOR_ENABLE;
+       tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+
+       value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL);
+       value &= ~CURSOR_DST_BLEND_MASK;
+       value &= ~CURSOR_SRC_BLEND_MASK;
+       value |= CURSOR_MODE_NORMAL;
+       value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC;
+       value |= CURSOR_SRC_BLEND_K1_TIMES_SRC;
+       value |= CURSOR_ALPHA;
+       tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL);
+
+       /* position the cursor */
+       value = (crtc_y & 0x3fff) << 16 | (crtc_x & 0x3fff);
+       tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);
+
+       /* apply changes */
+       tegra_dc_cursor_commit(dc);
+       tegra_dc_commit(dc);
+
+       return 0;
+}
+
+static int tegra_cursor_plane_disable(struct drm_plane *plane)
+{
+       struct tegra_dc *dc = to_tegra_dc(plane->crtc);
+       u32 value;
+
+       if (!plane->crtc)
+               return 0;
+
+       value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+       value &= ~CURSOR_ENABLE;
+       tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+
+       tegra_dc_cursor_commit(dc);
+       tegra_dc_commit(dc);
+
+       return 0;
+}
+
+static const struct drm_plane_funcs tegra_cursor_plane_funcs = {
+       .update_plane = tegra_cursor_plane_update,
+       .disable_plane = tegra_cursor_plane_disable,
+       .destroy = tegra_plane_destroy,
+};
+
+static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm,
+                                                     struct tegra_dc *dc)
+{
+       struct tegra_plane *plane;
+       unsigned int num_formats;
+       const u32 *formats;
+       int err;
+
+       plane = kzalloc(sizeof(*plane), GFP_KERNEL);
+       if (!plane)
+               return ERR_PTR(-ENOMEM);
+
+       num_formats = ARRAY_SIZE(tegra_cursor_plane_formats);
+       formats = tegra_cursor_plane_formats;
+
+       err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
+                                      &tegra_cursor_plane_funcs, formats,
+                                      num_formats, DRM_PLANE_TYPE_CURSOR);
+       if (err < 0) {
+               kfree(plane);
+               return ERR_PTR(err);
+       }
+
+       return &plane->base;
+}
+
+static int tegra_overlay_plane_update(struct drm_plane *plane,
+                                     struct drm_crtc *crtc,
+                                     struct drm_framebuffer *fb, int crtc_x,
+                                     int crtc_y, unsigned int crtc_w,
+                                     unsigned int crtc_h, uint32_t src_x,
+                                     uint32_t src_y, uint32_t src_w,
+                                     uint32_t src_h)
 {
        struct tegra_plane *p = to_tegra_plane(plane);
        struct tegra_dc *dc = to_tegra_dc(crtc);
@@ -361,44 +628,19 @@ static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
        return tegra_dc_setup_window(dc, p->index, &window);
 }
 
-static int tegra_plane_disable(struct drm_plane *plane)
+static void tegra_overlay_plane_destroy(struct drm_plane *plane)
 {
-       struct tegra_dc *dc = to_tegra_dc(plane->crtc);
-       struct tegra_plane *p = to_tegra_plane(plane);
-       unsigned long value;
-
-       if (!plane->crtc)
-               return 0;
-
-       value = WINDOW_A_SELECT << p->index;
-       tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
-
-       value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
-       value &= ~WIN_ENABLE;
-       tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
-
-       tegra_dc_writel(dc, WIN_A_UPDATE << p->index, DC_CMD_STATE_CONTROL);
-       tegra_dc_writel(dc, WIN_A_ACT_REQ << p->index, DC_CMD_STATE_CONTROL);
-
-       return 0;
-}
-
-static void tegra_plane_destroy(struct drm_plane *plane)
-{
-       struct tegra_plane *p = to_tegra_plane(plane);
-
-       tegra_plane_disable(plane);
-       drm_plane_cleanup(plane);
-       kfree(p);
+       tegra_window_plane_disable(plane);
+       tegra_plane_destroy(plane);
 }
 
-static const struct drm_plane_funcs tegra_plane_funcs = {
-       .update_plane = tegra_plane_update,
-       .disable_plane = tegra_plane_disable,
-       .destroy = tegra_plane_destroy,
+static const struct drm_plane_funcs tegra_overlay_plane_funcs = {
+       .update_plane = tegra_overlay_plane_update,
+       .disable_plane = tegra_window_plane_disable,
+       .destroy = tegra_overlay_plane_destroy,
 };
 
-static const uint32_t plane_formats[] = {
+static const uint32_t tegra_overlay_plane_formats[] = {
        DRM_FORMAT_XBGR8888,
        DRM_FORMAT_XRGB8888,
        DRM_FORMAT_RGB565,
@@ -408,27 +650,44 @@ static const uint32_t plane_formats[] = {
        DRM_FORMAT_YUV422,
 };
 
-static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
+static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
+                                                      struct tegra_dc *dc,
+                                                      unsigned int index)
 {
-       unsigned int i;
-       int err = 0;
+       struct tegra_plane *plane;
+       unsigned int num_formats;
+       const u32 *formats;
+       int err;
 
-       for (i = 0; i < 2; i++) {
-               struct tegra_plane *plane;
+       plane = kzalloc(sizeof(*plane), GFP_KERNEL);
+       if (!plane)
+               return ERR_PTR(-ENOMEM);
 
-               plane = kzalloc(sizeof(*plane), GFP_KERNEL);
-               if (!plane)
-                       return -ENOMEM;
+       plane->index = index;
 
-               plane->index = 1 + i;
+       num_formats = ARRAY_SIZE(tegra_overlay_plane_formats);
+       formats = tegra_overlay_plane_formats;
 
-               err = drm_plane_init(drm, &plane->base, 1 << dc->pipe,
-                                    &tegra_plane_funcs, plane_formats,
-                                    ARRAY_SIZE(plane_formats), false);
-               if (err < 0) {
-                       kfree(plane);
-                       return err;
-               }
+       err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
+                                      &tegra_overlay_plane_funcs, formats,
+                                      num_formats, DRM_PLANE_TYPE_OVERLAY);
+       if (err < 0) {
+               kfree(plane);
+               return ERR_PTR(err);
+       }
+
+       return &plane->base;
+}
+
+static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
+{
+       struct drm_plane *plane;
+       unsigned int i;
+
+       for (i = 0; i < 2; i++) {
+               plane = tegra_dc_overlay_plane_create(drm, dc, 1 + i);
+               if (IS_ERR(plane))
+                       return PTR_ERR(plane);
        }
 
        return 0;
@@ -515,10 +774,8 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
        tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET);
        tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET);
 
-       value = GENERAL_UPDATE | WIN_A_UPDATE;
-       tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
-
        value = GENERAL_ACT_REQ | WIN_A_ACT_REQ;
+       tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL);
        tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
 
        return 0;
@@ -550,109 +807,6 @@ void tegra_dc_disable_vblank(struct tegra_dc *dc)
        spin_unlock_irqrestore(&dc->lock, flags);
 }
 
-static int tegra_dc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file,
-                               uint32_t handle, uint32_t width,
-                               uint32_t height, int32_t hot_x, int32_t hot_y)
-{
-       unsigned long value = CURSOR_CLIP_DISPLAY;
-       struct tegra_dc *dc = to_tegra_dc(crtc);
-       struct drm_gem_object *gem;
-       struct tegra_bo *bo = NULL;
-
-       if (!dc->soc->supports_cursor)
-               return -ENXIO;
-
-       if (width != height)
-               return -EINVAL;
-
-       switch (width) {
-       case 32:
-               value |= CURSOR_SIZE_32x32;
-               break;
-
-       case 64:
-               value |= CURSOR_SIZE_64x64;
-               break;
-
-       case 128:
-               value |= CURSOR_SIZE_128x128;
-
-       case 256:
-               value |= CURSOR_SIZE_256x256;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       if (handle) {
-               gem = drm_gem_object_lookup(crtc->dev, file, handle);
-               if (!gem)
-                       return -ENOENT;
-
-               bo = to_tegra_bo(gem);
-       }
-
-       if (bo) {
-               unsigned long addr = (bo->paddr & 0xfffffc00) >> 10;
-#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
-               unsigned long high = (bo->paddr & 0xfffffffc) >> 32;
-#endif
-
-               tegra_dc_writel(dc, value | addr, DC_DISP_CURSOR_START_ADDR);
-
-#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
-               tegra_dc_writel(dc, high, DC_DISP_CURSOR_START_ADDR_HI);
-#endif
-
-               value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
-               value |= CURSOR_ENABLE;
-               tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
-
-               value = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL);
-               value &= ~CURSOR_DST_BLEND_MASK;
-               value &= ~CURSOR_SRC_BLEND_MASK;
-               value |= CURSOR_MODE_NORMAL;
-               value |= CURSOR_DST_BLEND_NEG_K1_TIMES_SRC;
-               value |= CURSOR_SRC_BLEND_K1_TIMES_SRC;
-               value |= CURSOR_ALPHA;
-               tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL);
-       } else {
-               value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
-               value &= ~CURSOR_ENABLE;
-               tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
-       }
-
-       tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
-       tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);
-
-       tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
-       tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
-
-       return 0;
-}
-
-static int tegra_dc_cursor_move(struct drm_crtc *crtc, int x, int y)
-{
-       struct tegra_dc *dc = to_tegra_dc(crtc);
-       unsigned long value;
-
-       if (!dc->soc->supports_cursor)
-               return -ENXIO;
-
-       value = ((y & 0x3fff) << 16) | (x & 0x3fff);
-       tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);
-
-       tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
-       tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);
-
-       /* XXX: only required on generations earlier than Tegra124? */
-       tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
-       tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
-
-       return 0;
-}
-
 static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
 {
        struct drm_device *drm = dc->base.dev;
@@ -729,8 +883,6 @@ static void tegra_dc_destroy(struct drm_crtc *crtc)
 }
 
 static const struct drm_crtc_funcs tegra_crtc_funcs = {
-       .cursor_set2 = tegra_dc_cursor_set2,
-       .cursor_move = tegra_dc_cursor_move,
        .page_flip = tegra_dc_page_flip,
        .set_config = drm_crtc_helper_set_config,
        .destroy = tegra_dc_destroy,
@@ -738,12 +890,13 @@ static const struct drm_crtc_funcs tegra_crtc_funcs = {
 
 static void tegra_crtc_disable(struct drm_crtc *crtc)
 {
+       struct tegra_dc *dc = to_tegra_dc(crtc);
        struct drm_device *drm = crtc->dev;
        struct drm_plane *plane;
 
        drm_for_each_legacy_plane(plane, &drm->mode_config.plane_list) {
                if (plane->crtc == crtc) {
-                       tegra_plane_disable(plane);
+                       tegra_window_plane_disable(plane);
                        plane->crtc = NULL;
 
                        if (plane->fb) {
@@ -754,6 +907,7 @@ static void tegra_crtc_disable(struct drm_crtc *crtc)
        }
 
        drm_crtc_vblank_off(crtc);
+       tegra_dc_commit(dc);
 }
 
 static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -936,15 +1090,9 @@ static void tegra_crtc_prepare(struct drm_crtc *crtc)
 static void tegra_crtc_commit(struct drm_crtc *crtc)
 {
        struct tegra_dc *dc = to_tegra_dc(crtc);
-       unsigned long value;
-
-       value = GENERAL_UPDATE | WIN_A_UPDATE;
-       tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
-
-       value = GENERAL_ACT_REQ | WIN_A_ACT_REQ;
-       tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
 
        drm_crtc_vblank_on(crtc);
+       tegra_dc_commit(dc);
 }
 
 static void tegra_crtc_load_lut(struct drm_crtc *crtc)
@@ -998,7 +1146,7 @@ static int tegra_dc_show_regs(struct seq_file *s, void *data)
        struct tegra_dc *dc = node->info_ent->data;
 
 #define DUMP_REG(name)                                         \
-       seq_printf(s, "%-40s %#05x %08lx\n", #name, name,       \
+       seq_printf(s, "%-40s %#05x %08x\n", #name, name,        \
                   tegra_dc_readl(dc, name))
 
        DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT);
@@ -1286,9 +1434,40 @@ static int tegra_dc_init(struct host1x_client *client)
        struct drm_device *drm = dev_get_drvdata(client->parent);
        struct tegra_dc *dc = host1x_client_to_dc(client);
        struct tegra_drm *tegra = drm->dev_private;
+       struct drm_plane *primary = NULL;
+       struct drm_plane *cursor = NULL;
        int err;
 
-       drm_crtc_init(drm, &dc->base, &tegra_crtc_funcs);
+       if (tegra->domain) {
+               err = iommu_attach_device(tegra->domain, dc->dev);
+               if (err < 0) {
+                       dev_err(dc->dev, "failed to attach to domain: %d\n",
+                               err);
+                       return err;
+               }
+
+               dc->domain = tegra->domain;
+       }
+
+       primary = tegra_dc_primary_plane_create(drm, dc);
+       if (IS_ERR(primary)) {
+               err = PTR_ERR(primary);
+               goto cleanup;
+       }
+
+       if (dc->soc->supports_cursor) {
+               cursor = tegra_dc_cursor_plane_create(drm, dc);
+               if (IS_ERR(cursor)) {
+                       err = PTR_ERR(cursor);
+                       goto cleanup;
+               }
+       }
+
+       err = drm_crtc_init_with_planes(drm, &dc->base, primary, cursor,
+                                       &tegra_crtc_funcs);
+       if (err < 0)
+               goto cleanup;
+
        drm_mode_crtc_set_gamma_size(&dc->base, 256);
        drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs);
 
@@ -1302,12 +1481,12 @@ static int tegra_dc_init(struct host1x_client *client)
        err = tegra_dc_rgb_init(drm, dc);
        if (err < 0 && err != -ENODEV) {
                dev_err(dc->dev, "failed to initialize RGB output: %d\n", err);
-               return err;
+               goto cleanup;
        }
 
        err = tegra_dc_add_planes(drm, dc);
        if (err < 0)
-               return err;
+               goto cleanup;
 
        if (IS_ENABLED(CONFIG_DEBUG_FS)) {
                err = tegra_dc_debugfs_init(dc, drm->primary);
@@ -1320,10 +1499,24 @@ static int tegra_dc_init(struct host1x_client *client)
        if (err < 0) {
                dev_err(dc->dev, "failed to request IRQ#%u: %d\n", dc->irq,
                        err);
-               return err;
+               goto cleanup;
        }
 
        return 0;
+
+cleanup:
+       if (cursor)
+               drm_plane_cleanup(cursor);
+
+       if (primary)
+               drm_plane_cleanup(primary);
+
+       if (tegra->domain) {
+               iommu_detach_device(tegra->domain, dc->dev);
+               dc->domain = NULL;
+       }
+
+       return err;
 }
 
 static int tegra_dc_exit(struct host1x_client *client)
@@ -1345,6 +1538,11 @@ static int tegra_dc_exit(struct host1x_client *client)
                return err;
        }
 
+       if (dc->domain) {
+               iommu_detach_device(dc->domain, dc->dev);
+               dc->domain = NULL;
+       }
+
        return 0;
 }
 
@@ -1358,6 +1556,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
        .supports_cursor = false,
        .supports_block_linear = false,
        .pitch_align = 8,
+       .has_powergate = false,
 };
 
 static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
@@ -1365,6 +1564,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
        .supports_cursor = false,
        .supports_block_linear = false,
        .pitch_align = 8,
+       .has_powergate = false,
 };
 
 static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
@@ -1372,6 +1572,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
        .supports_cursor = false,
        .supports_block_linear = false,
        .pitch_align = 64,
+       .has_powergate = true,
 };
 
 static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
@@ -1379,12 +1580,16 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
        .supports_cursor = true,
        .supports_block_linear = true,
        .pitch_align = 64,
+       .has_powergate = true,
 };
 
 static const struct of_device_id tegra_dc_of_match[] = {
        {
                .compatible = "nvidia,tegra124-dc",
                .data = &tegra124_dc_soc_info,
+       }, {
+               .compatible = "nvidia,tegra114-dc",
+               .data = &tegra114_dc_soc_info,
        }, {
                .compatible = "nvidia,tegra30-dc",
                .data = &tegra30_dc_soc_info,
@@ -1468,9 +1673,34 @@ static int tegra_dc_probe(struct platform_device *pdev)
                return PTR_ERR(dc->rst);
        }
 
-       err = clk_prepare_enable(dc->clk);
-       if (err < 0)
-               return err;
+       if (dc->soc->has_powergate) {
+               if (dc->pipe == 0)
+                       dc->powergate = TEGRA_POWERGATE_DIS;
+               else
+                       dc->powergate = TEGRA_POWERGATE_DISB;
+
+               err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk,
+                                                       dc->rst);
+               if (err < 0) {
+                       dev_err(&pdev->dev, "failed to power partition: %d\n",
+                               err);
+                       return err;
+               }
+       } else {
+               err = clk_prepare_enable(dc->clk);
+               if (err < 0) {
+                       dev_err(&pdev->dev, "failed to enable clock: %d\n",
+                               err);
+                       return err;
+               }
+
+               err = reset_control_deassert(dc->rst);
+               if (err < 0) {
+                       dev_err(&pdev->dev, "failed to deassert reset: %d\n",
+                               err);
+                       return err;
+               }
+       }
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        dc->regs = devm_ioremap_resource(&pdev->dev, regs);
@@ -1524,6 +1754,10 @@ static int tegra_dc_remove(struct platform_device *pdev)
        }
 
        reset_control_assert(dc->rst);
+
+       if (dc->soc->has_powergate)
+               tegra_powergate_power_off(dc->powergate);
+
        clk_disable_unprepare(dc->clk);
 
        return 0;
index 59736bb810cd2d4787dab77d1fea29dadcf30f9f..e549afeece1ff12c899afc9f21dd52ff5e3e64ff 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/host1x.h>
+#include <linux/iommu.h>
 
 #include "drm.h"
 #include "gem.h"
@@ -33,6 +34,17 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
        if (!tegra)
                return -ENOMEM;
 
+       if (iommu_present(&platform_bus_type)) {
+               tegra->domain = iommu_domain_alloc(&platform_bus_type);
+               if (IS_ERR(tegra->domain)) {
+                       err = PTR_ERR(tegra->domain);
+                       goto free;
+               }
+
+               DRM_DEBUG("IOMMU context initialized\n");
+               drm_mm_init(&tegra->mm, 0, SZ_2G);
+       }
+
        mutex_init(&tegra->clients_lock);
        INIT_LIST_HEAD(&tegra->clients);
        drm->dev_private = tegra;
@@ -42,13 +54,13 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
 
        err = tegra_drm_fb_prepare(drm);
        if (err < 0)
-               return err;
+               goto config;
 
        drm_kms_helper_poll_init(drm);
 
        err = host1x_device_init(device);
        if (err < 0)
-               return err;
+               goto fbdev;
 
        /*
         * We don't use the drm_irq_install() helpers provided by the DRM
@@ -59,18 +71,37 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
 
        err = drm_vblank_init(drm, drm->mode_config.num_crtc);
        if (err < 0)
-               return err;
+               goto device;
 
        err = tegra_drm_fb_init(drm);
        if (err < 0)
-               return err;
+               goto vblank;
 
        return 0;
+
+vblank:
+       drm_vblank_cleanup(drm);
+device:
+       host1x_device_exit(device);
+fbdev:
+       drm_kms_helper_poll_fini(drm);
+       tegra_drm_fb_free(drm);
+config:
+       drm_mode_config_cleanup(drm);
+
+       if (tegra->domain) {
+               iommu_domain_free(tegra->domain);
+               drm_mm_takedown(&tegra->mm);
+       }
+free:
+       kfree(tegra);
+       return err;
 }
 
 static int tegra_drm_unload(struct drm_device *drm)
 {
        struct host1x_device *device = to_host1x_device(drm->dev);
+       struct tegra_drm *tegra = drm->dev_private;
        int err;
 
        drm_kms_helper_poll_fini(drm);
@@ -82,6 +113,13 @@ static int tegra_drm_unload(struct drm_device *drm)
        if (err < 0)
                return err;
 
+       if (tegra->domain) {
+               iommu_domain_free(tegra->domain);
+               drm_mm_takedown(&tegra->mm);
+       }
+
+       kfree(tegra);
+
        return 0;
 }
 
index e89c70fa82d554f3da8fced5ae99b840e56c985f..3a3b2e7b5b3f0f7902e03a32cdcaba65f20c8cdf 100644 (file)
@@ -39,6 +39,9 @@ struct tegra_fbdev {
 struct tegra_drm {
        struct drm_device *drm;
 
+       struct iommu_domain *domain;
+       struct drm_mm mm;
+
        struct mutex clients_lock;
        struct list_head clients;
 
@@ -101,6 +104,7 @@ struct tegra_dc {
        spinlock_t lock;
 
        struct drm_crtc base;
+       int powergate;
        int pipe;
 
        struct clk *clk;
@@ -120,6 +124,8 @@ struct tegra_dc {
        struct drm_pending_vblank_event *event;
 
        const struct tegra_dc_soc_info *soc;
+
+       struct iommu_domain *domain;
 };
 
 static inline struct tegra_dc *
@@ -133,16 +139,15 @@ static inline struct tegra_dc *to_tegra_dc(struct drm_crtc *crtc)
        return crtc ? container_of(crtc, struct tegra_dc, base) : NULL;
 }
 
-static inline void tegra_dc_writel(struct tegra_dc *dc, unsigned long value,
-                                  unsigned long reg)
+static inline void tegra_dc_writel(struct tegra_dc *dc, u32 value,
+                                  unsigned long offset)
 {
-       writel(value, dc->regs + (reg << 2));
+       writel(value, dc->regs + (offset << 2));
 }
 
-static inline unsigned long tegra_dc_readl(struct tegra_dc *dc,
-                                          unsigned long reg)
+static inline u32 tegra_dc_readl(struct tegra_dc *dc, unsigned long offset)
 {
-       return readl(dc->regs + (reg << 2));
+       return readl(dc->regs + (offset << 2));
 }
 
 struct tegra_dc_window {
@@ -287,6 +292,7 @@ bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer);
 int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer,
                        struct tegra_bo_tiling *tiling);
 int tegra_drm_fb_prepare(struct drm_device *drm);
+void tegra_drm_fb_free(struct drm_device *drm);
 int tegra_drm_fb_init(struct drm_device *drm);
 void tegra_drm_fb_exit(struct drm_device *drm);
 #ifdef CONFIG_DRM_TEGRA_FBDEV
index f7874458926a7f289d8df1a3e46ead9f066e1a82..33f67fd601c6076670496617d51366050f327238 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/host1x.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/reset.h>
 
@@ -26,9 +27,6 @@
 #include "dsi.h"
 #include "mipi-phy.h"
 
-#define DSI_VIDEO_FIFO_DEPTH (1920 / 4)
-#define DSI_HOST_FIFO_DEPTH 64
-
 struct tegra_dsi {
        struct host1x_client client;
        struct tegra_output output;
@@ -54,6 +52,13 @@ struct tegra_dsi {
 
        struct regulator *vdd;
        bool enabled;
+
+       unsigned int video_fifo_depth;
+       unsigned int host_fifo_depth;
+
+       /* for ganged-mode support */
+       struct tegra_dsi *master;
+       struct tegra_dsi *slave;
 };
 
 static inline struct tegra_dsi *
@@ -318,6 +323,21 @@ static const u32 pkt_seq_video_non_burst_sync_events[NUM_PKT_SEQ] = {
        [11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
 };
 
+static const u32 pkt_seq_command_mode[NUM_PKT_SEQ] = {
+       [ 0] = 0,
+       [ 1] = 0,
+       [ 2] = 0,
+       [ 3] = 0,
+       [ 4] = 0,
+       [ 5] = 0,
+       [ 6] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(3) | PKT_LP,
+       [ 7] = 0,
+       [ 8] = 0,
+       [ 9] = 0,
+       [10] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(5) | PKT_LP,
+       [11] = 0,
+};
+
 static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
 {
        struct mipi_dphy_timing timing;
@@ -329,7 +349,7 @@ static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
        if (rate < 0)
                return rate;
 
-       period = DIV_ROUND_CLOSEST(1000000000UL, rate * 2);
+       period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate * 2);
 
        err = mipi_dphy_timing_get_default(&timing, period);
        if (err < 0)
@@ -369,6 +389,9 @@ static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
                DSI_TIMING_FIELD(timing.tago, period, 1);
        tegra_dsi_writel(dsi, value, DSI_BTA_TIMING);
 
+       if (dsi->slave)
+               return tegra_dsi_set_phy_timing(dsi->slave);
+
        return 0;
 }
 
@@ -426,26 +449,59 @@ static int tegra_dsi_get_format(enum mipi_dsi_pixel_format format,
        return 0;
 }
 
-static int tegra_output_dsi_enable(struct tegra_output *output)
+static void tegra_dsi_ganged_enable(struct tegra_dsi *dsi, unsigned int start,
+                                   unsigned int size)
+{
+       u32 value;
+
+       tegra_dsi_writel(dsi, start, DSI_GANGED_MODE_START);
+       tegra_dsi_writel(dsi, size << 16 | size, DSI_GANGED_MODE_SIZE);
+
+       value = DSI_GANGED_MODE_CONTROL_ENABLE;
+       tegra_dsi_writel(dsi, value, DSI_GANGED_MODE_CONTROL);
+}
+
+static void tegra_dsi_enable(struct tegra_dsi *dsi)
+{
+       u32 value;
+
+       value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
+       value |= DSI_POWER_CONTROL_ENABLE;
+       tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
+
+       if (dsi->slave)
+               tegra_dsi_enable(dsi->slave);
+}
+
+static unsigned int tegra_dsi_get_lanes(struct tegra_dsi *dsi)
+{
+       if (dsi->master)
+               return dsi->master->lanes + dsi->lanes;
+
+       if (dsi->slave)
+               return dsi->lanes + dsi->slave->lanes;
+
+       return dsi->lanes;
+}
+
+static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
+                              const struct drm_display_mode *mode)
 {
-       struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
-       struct drm_display_mode *mode = &dc->base.mode;
        unsigned int hact, hsw, hbp, hfp, i, mul, div;
-       struct tegra_dsi *dsi = to_dsi(output);
        enum tegra_dsi_format format;
-       unsigned long value;
        const u32 *pkt_seq;
+       u32 value;
        int err;
 
-       if (dsi->enabled)
-               return 0;
-
        if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
                DRM_DEBUG_KMS("Non-burst video mode with sync pulses\n");
                pkt_seq = pkt_seq_video_non_burst_sync_pulses;
-       } else {
+       } else if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
                DRM_DEBUG_KMS("Non-burst video mode with sync events\n");
                pkt_seq = pkt_seq_video_non_burst_sync_events;
+       } else {
+               DRM_DEBUG_KMS("Command mode\n");
+               pkt_seq = pkt_seq_command_mode;
        }
 
        err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
@@ -456,61 +512,136 @@ static int tegra_output_dsi_enable(struct tegra_output *output)
        if (err < 0)
                return err;
 
-       err = clk_enable(dsi->clk);
-       if (err < 0)
-               return err;
-
-       reset_control_deassert(dsi->rst);
-
        value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(format) |
                DSI_CONTROL_LANES(dsi->lanes - 1) |
-               DSI_CONTROL_SOURCE(dc->pipe);
+               DSI_CONTROL_SOURCE(pipe);
        tegra_dsi_writel(dsi, value, DSI_CONTROL);
 
-       tegra_dsi_writel(dsi, DSI_VIDEO_FIFO_DEPTH, DSI_MAX_THRESHOLD);
+       tegra_dsi_writel(dsi, dsi->video_fifo_depth, DSI_MAX_THRESHOLD);
 
-       value = DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_CS |
-               DSI_HOST_CONTROL_ECC;
+       value = DSI_HOST_CONTROL_HS;
        tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
 
        value = tegra_dsi_readl(dsi, DSI_CONTROL);
+
        if (dsi->flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
                value |= DSI_CONTROL_HS_CLK_CTRL;
+
        value &= ~DSI_CONTROL_TX_TRIG(3);
-       value &= ~DSI_CONTROL_DCS_ENABLE;
+
+       /* enable DCS commands for command mode */
+       if (dsi->flags & MIPI_DSI_MODE_VIDEO)
+               value &= ~DSI_CONTROL_DCS_ENABLE;
+       else
+               value |= DSI_CONTROL_DCS_ENABLE;
+
        value |= DSI_CONTROL_VIDEO_ENABLE;
        value &= ~DSI_CONTROL_HOST_ENABLE;
        tegra_dsi_writel(dsi, value, DSI_CONTROL);
 
-       err = tegra_dsi_set_phy_timing(dsi);
-       if (err < 0)
-               return err;
-
        for (i = 0; i < NUM_PKT_SEQ; i++)
                tegra_dsi_writel(dsi, pkt_seq[i], DSI_PKT_SEQ_0_LO + i);
 
-       /* horizontal active pixels */
-       hact = mode->hdisplay * mul / div;
+       if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
+               /* horizontal active pixels */
+               hact = mode->hdisplay * mul / div;
 
-       /* horizontal sync width */
-       hsw = (mode->hsync_end - mode->hsync_start) * mul / div;
-       hsw -= 10;
+               /* horizontal sync width */
+               hsw = (mode->hsync_end - mode->hsync_start) * mul / div;
+               hsw -= 10;
 
-       /* horizontal back porch */
-       hbp = (mode->htotal - mode->hsync_end) * mul / div;
-       hbp -= 14;
+               /* horizontal back porch */
+               hbp = (mode->htotal - mode->hsync_end) * mul / div;
+               hbp -= 14;
 
-       /* horizontal front porch */
-       hfp = (mode->hsync_start  - mode->hdisplay) * mul / div;
-       hfp -= 8;
+               /* horizontal front porch */
+               hfp = (mode->hsync_start - mode->hdisplay) * mul / div;
+               hfp -= 8;
 
-       tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1);
-       tegra_dsi_writel(dsi, hact << 16 | hbp, DSI_PKT_LEN_2_3);
-       tegra_dsi_writel(dsi, hfp, DSI_PKT_LEN_4_5);
-       tegra_dsi_writel(dsi, 0x0f0f << 16, DSI_PKT_LEN_6_7);
+               tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1);
+               tegra_dsi_writel(dsi, hact << 16 | hbp, DSI_PKT_LEN_2_3);
+               tegra_dsi_writel(dsi, hfp, DSI_PKT_LEN_4_5);
+               tegra_dsi_writel(dsi, 0x0f0f << 16, DSI_PKT_LEN_6_7);
 
-       /* set SOL delay */
-       tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY);
+               /* set SOL delay (for non-burst mode only) */
+               tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY);
+
+               /* TODO: implement ganged mode */
+       } else {
+               u16 bytes;
+
+               if (dsi->master || dsi->slave) {
+                       /*
+                        * For ganged mode, assume symmetric left-right mode.
+                        */
+                       bytes = 1 + (mode->hdisplay / 2) * mul / div;
+               } else {
+                       /* 1 byte (DCS command) + pixel data */
+                       bytes = 1 + mode->hdisplay * mul / div;
+               }
+
+               tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1);
+               tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_2_3);
+               tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_4_5);
+               tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_6_7);
+
+               value = MIPI_DCS_WRITE_MEMORY_START << 8 |
+                       MIPI_DCS_WRITE_MEMORY_CONTINUE;
+               tegra_dsi_writel(dsi, value, DSI_DCS_CMDS);
+
+               /* set SOL delay */
+               if (dsi->master || dsi->slave) {
+                       unsigned int lanes = tegra_dsi_get_lanes(dsi);
+                       unsigned long delay, bclk, bclk_ganged;
+
+                       /* SOL to valid, valid to FIFO and FIFO write delay */
+                       delay = 4 + 4 + 2;
+                       delay = DIV_ROUND_UP(delay * mul, div * lanes);
+                       /* FIFO read delay */
+                       delay = delay + 6;
+
+                       bclk = DIV_ROUND_UP(mode->htotal * mul, div * lanes);
+                       bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes);
+                       value = bclk - bclk_ganged + delay + 20;
+               } else {
+                       /* TODO: revisit for non-ganged mode */
+                       value = 8 * mul / div;
+               }
+
+               tegra_dsi_writel(dsi, value, DSI_SOL_DELAY);
+       }
+
+       if (dsi->slave) {
+               err = tegra_dsi_configure(dsi->slave, pipe, mode);
+               if (err < 0)
+                       return err;
+
+               /*
+                * TODO: Support modes other than symmetrical left-right
+                * split.
+                */
+               tegra_dsi_ganged_enable(dsi, 0, mode->hdisplay / 2);
+               tegra_dsi_ganged_enable(dsi->slave, mode->hdisplay / 2,
+                                       mode->hdisplay / 2);
+       }
+
+       return 0;
+}
+
+static int tegra_output_dsi_enable(struct tegra_output *output)
+{
+       struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
+       const struct drm_display_mode *mode = &dc->base.mode;
+       struct tegra_dsi *dsi = to_dsi(output);
+       u32 value;
+       int err;
+
+       if (dsi->enabled)
+               return 0;
+
+       err = tegra_dsi_configure(dsi, dc->pipe, mode);
+       if (err < 0)
+               return err;
 
        /* enable display controller */
        value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
@@ -531,28 +662,79 @@ static int tegra_output_dsi_enable(struct tegra_output *output)
        tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
 
        /* enable DSI controller */
-       value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
-       value |= DSI_POWER_CONTROL_ENABLE;
-       tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
+       tegra_dsi_enable(dsi);
 
        dsi->enabled = true;
 
        return 0;
 }
 
+static int tegra_dsi_wait_idle(struct tegra_dsi *dsi, unsigned long timeout)
+{
+       u32 value;
+
+       timeout = jiffies + msecs_to_jiffies(timeout);
+
+       while (time_before(jiffies, timeout)) {
+               value = tegra_dsi_readl(dsi, DSI_STATUS);
+               if (value & DSI_STATUS_IDLE)
+                       return 0;
+
+               usleep_range(1000, 2000);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static void tegra_dsi_video_disable(struct tegra_dsi *dsi)
+{
+       u32 value;
+
+       value = tegra_dsi_readl(dsi, DSI_CONTROL);
+       value &= ~DSI_CONTROL_VIDEO_ENABLE;
+       tegra_dsi_writel(dsi, value, DSI_CONTROL);
+
+       if (dsi->slave)
+               tegra_dsi_video_disable(dsi->slave);
+}
+
+static void tegra_dsi_ganged_disable(struct tegra_dsi *dsi)
+{
+       tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_START);
+       tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_SIZE);
+       tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL);
+}
+
+static void tegra_dsi_disable(struct tegra_dsi *dsi)
+{
+       u32 value;
+
+       if (dsi->slave) {
+               tegra_dsi_ganged_disable(dsi->slave);
+               tegra_dsi_ganged_disable(dsi);
+       }
+
+       value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
+       value &= ~DSI_POWER_CONTROL_ENABLE;
+       tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
+
+       if (dsi->slave)
+               tegra_dsi_disable(dsi->slave);
+
+       usleep_range(5000, 10000);
+}
+
 static int tegra_output_dsi_disable(struct tegra_output *output)
 {
        struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
        struct tegra_dsi *dsi = to_dsi(output);
        unsigned long value;
+       int err;
 
        if (!dsi->enabled)
                return 0;
 
-       /* disable DSI controller */
-       value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
-       value &= ~DSI_POWER_CONTROL_ENABLE;
-       tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
+       tegra_dsi_video_disable(dsi);
 
        /*
         * The following accesses registers of the display controller, so make
@@ -576,39 +758,68 @@ static int tegra_output_dsi_disable(struct tegra_output *output)
                tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
        }
 
-       clk_disable(dsi->clk);
+       err = tegra_dsi_wait_idle(dsi, 100);
+       if (err < 0)
+               dev_dbg(dsi->dev, "failed to idle DSI: %d\n", err);
+
+       tegra_dsi_disable(dsi);
 
        dsi->enabled = false;
 
        return 0;
 }
 
+static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk,
+                                 unsigned int vrefresh)
+{
+       unsigned int timeout;
+       u32 value;
+
+       /* one frame high-speed transmission timeout */
+       timeout = (bclk / vrefresh) / 512;
+       value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout);
+       tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0);
+
+       /* 2 ms peripheral timeout for panel */
+       timeout = 2 * bclk / 512 * 1000;
+       value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000);
+       tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1);
+
+       value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0);
+       tegra_dsi_writel(dsi, value, DSI_TO_TALLY);
+
+       if (dsi->slave)
+               tegra_dsi_set_timeout(dsi->slave, bclk, vrefresh);
+}
+
 static int tegra_output_dsi_setup_clock(struct tegra_output *output,
                                        struct clk *clk, unsigned long pclk,
                                        unsigned int *divp)
 {
        struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
        struct drm_display_mode *mode = &dc->base.mode;
-       unsigned int timeout, mul, div, vrefresh;
        struct tegra_dsi *dsi = to_dsi(output);
-       unsigned long bclk, plld, value;
+       unsigned int mul, div, vrefresh, lanes;
+       unsigned long bclk, plld;
        int err;
 
+       lanes = tegra_dsi_get_lanes(dsi);
+
        err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
        if (err < 0)
                return err;
 
-       DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", mul, div, dsi->lanes);
+       DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", mul, div, lanes);
        vrefresh = drm_mode_vrefresh(mode);
        DRM_DEBUG_KMS("vrefresh: %u\n", vrefresh);
 
        /* compute byte clock */
-       bclk = (pclk * mul) / (div * dsi->lanes);
+       bclk = (pclk * mul) / (div * lanes);
 
        /*
         * Compute bit clock and round up to the next MHz.
         */
-       plld = DIV_ROUND_UP(bclk * 8, 1000000) * 1000000;
+       plld = DIV_ROUND_UP(bclk * 8, USEC_PER_SEC) * USEC_PER_SEC;
 
        /*
         * We divide the frequency by two here, but we make up for that by
@@ -640,25 +851,17 @@ static int tegra_output_dsi_setup_clock(struct tegra_output *output,
         * not working properly otherwise. Perhaps the PLLs cannot generate
         * frequencies sufficiently high.
         */
-       *divp = ((8 * mul) / (div * dsi->lanes)) - 2;
+       *divp = ((8 * mul) / (div * lanes)) - 2;
 
        /*
         * XXX: Move the below somewhere else so that we don't need to have
         * access to the vrefresh in this function?
         */
+       tegra_dsi_set_timeout(dsi, bclk, vrefresh);
 
-       /* one frame high-speed transmission timeout */
-       timeout = (bclk / vrefresh) / 512;
-       value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout);
-       tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0);
-
-       /* 2 ms peripheral timeout for panel */
-       timeout = 2 * bclk / 512 * 1000;
-       value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000);
-       tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1);
-
-       value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0);
-       tegra_dsi_writel(dsi, value, DSI_TO_TALLY);
+       err = tegra_dsi_set_phy_timing(dsi);
+       if (err < 0)
+               return err;
 
        return 0;
 }
@@ -695,7 +898,7 @@ static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
 
 static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
 {
-       unsigned long value;
+       u32 value;
 
        tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
        tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
@@ -720,14 +923,17 @@ static int tegra_dsi_init(struct host1x_client *client)
        struct tegra_dsi *dsi = host1x_client_to_dsi(client);
        int err;
 
-       dsi->output.type = TEGRA_OUTPUT_DSI;
-       dsi->output.dev = client->dev;
-       dsi->output.ops = &dsi_ops;
-
-       err = tegra_output_init(drm, &dsi->output);
-       if (err < 0) {
-               dev_err(client->dev, "output setup failed: %d\n", err);
-               return err;
+       /* Gangsters must not register their own outputs. */
+       if (!dsi->master) {
+               dsi->output.type = TEGRA_OUTPUT_DSI;
+               dsi->output.dev = client->dev;
+               dsi->output.ops = &dsi_ops;
+
+               err = tegra_output_init(drm, &dsi->output);
+               if (err < 0) {
+                       dev_err(client->dev, "output setup failed: %d\n", err);
+                       return err;
+               }
        }
 
        if (IS_ENABLED(CONFIG_DEBUG_FS)) {
@@ -736,12 +942,6 @@ static int tegra_dsi_init(struct host1x_client *client)
                        dev_err(dsi->dev, "debugfs setup failed: %d\n", err);
        }
 
-       err = tegra_dsi_pad_calibrate(dsi);
-       if (err < 0) {
-               dev_err(dsi->dev, "MIPI calibration failed: %d\n", err);
-               return err;
-       }
-
        return 0;
 }
 
@@ -756,16 +956,20 @@ static int tegra_dsi_exit(struct host1x_client *client)
                        dev_err(dsi->dev, "debugfs cleanup failed: %d\n", err);
        }
 
-       err = tegra_output_disable(&dsi->output);
-       if (err < 0) {
-               dev_err(client->dev, "output failed to disable: %d\n", err);
-               return err;
-       }
-
-       err = tegra_output_exit(&dsi->output);
-       if (err < 0) {
-               dev_err(client->dev, "output cleanup failed: %d\n", err);
-               return err;
+       if (!dsi->master) {
+               err = tegra_output_disable(&dsi->output);
+               if (err < 0) {
+                       dev_err(client->dev, "output failed to disable: %d\n",
+                               err);
+                       return err;
+               }
+
+               err = tegra_output_exit(&dsi->output);
+               if (err < 0) {
+                       dev_err(client->dev, "output cleanup failed: %d\n",
+                               err);
+                       return err;
+               }
        }
 
        return 0;
@@ -792,20 +996,324 @@ static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi)
        return 0;
 }
 
+static const char * const error_report[16] = {
+       "SoT Error",
+       "SoT Sync Error",
+       "EoT Sync Error",
+       "Escape Mode Entry Command Error",
+       "Low-Power Transmit Sync Error",
+       "Peripheral Timeout Error",
+       "False Control Error",
+       "Contention Detected",
+       "ECC Error, single-bit",
+       "ECC Error, multi-bit",
+       "Checksum Error",
+       "DSI Data Type Not Recognized",
+       "DSI VC ID Invalid",
+       "Invalid Transmission Length",
+       "Reserved",
+       "DSI Protocol Violation",
+};
+
+static ssize_t tegra_dsi_read_response(struct tegra_dsi *dsi,
+                                      const struct mipi_dsi_msg *msg,
+                                      size_t count)
+{
+       u8 *rx = msg->rx_buf;
+       unsigned int i, j, k;
+       size_t size = 0;
+       u16 errors;
+       u32 value;
+
+       /* read and parse packet header */
+       value = tegra_dsi_readl(dsi, DSI_RD_DATA);
+
+       switch (value & 0x3f) {
+       case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
+               errors = (value >> 8) & 0xffff;
+               dev_dbg(dsi->dev, "Acknowledge and error report: %04x\n",
+                       errors);
+               for (i = 0; i < ARRAY_SIZE(error_report); i++)
+                       if (errors & BIT(i))
+                               dev_dbg(dsi->dev, "  %2u: %s\n", i,
+                                       error_report[i]);
+               break;
+
+       case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
+               rx[0] = (value >> 8) & 0xff;
+               size = 1;
+               break;
+
+       case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
+               rx[0] = (value >>  8) & 0xff;
+               rx[1] = (value >> 16) & 0xff;
+               size = 2;
+               break;
+
+       case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
+               size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
+               break;
+
+       case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
+               size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
+               break;
+
+       default:
+               dev_err(dsi->dev, "unhandled response type: %02x\n",
+                       value & 0x3f);
+               return -EPROTO;
+       }
+
+       size = min(size, msg->rx_len);
+
+       if (msg->rx_buf && size > 0) {
+               for (i = 0, j = 0; i < count - 1; i++, j += 4) {
+                       u8 *rx = msg->rx_buf + j;
+
+                       value = tegra_dsi_readl(dsi, DSI_RD_DATA);
+
+                       for (k = 0; k < 4 && (j + k) < msg->rx_len; k++)
+                               rx[j + k] = (value >> (k << 3)) & 0xff;
+               }
+       }
+
+       return size;
+}
+
+static int tegra_dsi_transmit(struct tegra_dsi *dsi, unsigned long timeout)
+{
+       tegra_dsi_writel(dsi, DSI_TRIGGER_HOST, DSI_TRIGGER);
+
+       timeout = jiffies + msecs_to_jiffies(timeout);
+
+       while (time_before(jiffies, timeout)) {
+               u32 value = tegra_dsi_readl(dsi, DSI_TRIGGER);
+               if ((value & DSI_TRIGGER_HOST) == 0)
+                       return 0;
+
+               usleep_range(1000, 2000);
+       }
+
+       DRM_DEBUG_KMS("timeout waiting for transmission to complete\n");
+       return -ETIMEDOUT;
+}
+
+static int tegra_dsi_wait_for_response(struct tegra_dsi *dsi,
+                                      unsigned long timeout)
+{
+       timeout = jiffies + msecs_to_jiffies(250);
+
+       while (time_before(jiffies, timeout)) {
+               u32 value = tegra_dsi_readl(dsi, DSI_STATUS);
+               u8 count = value & 0x1f;
+
+               if (count > 0)
+                       return count;
+
+               usleep_range(1000, 2000);
+       }
+
+       DRM_DEBUG_KMS("peripheral returned no data\n");
+       return -ETIMEDOUT;
+}
+
+static void tegra_dsi_writesl(struct tegra_dsi *dsi, unsigned long offset,
+                             const void *buffer, size_t size)
+{
+       const u8 *buf = buffer;
+       size_t i, j;
+       u32 value;
+
+       for (j = 0; j < size; j += 4) {
+               value = 0;
+
+               for (i = 0; i < 4 && j + i < size; i++)
+                       value |= buf[j + i] << (i << 3);
+
+               tegra_dsi_writel(dsi, value, DSI_WR_DATA);
+       }
+}
+
+static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host,
+                                      const struct mipi_dsi_msg *msg)
+{
+       struct tegra_dsi *dsi = host_to_tegra(host);
+       struct mipi_dsi_packet packet;
+       const u8 *header;
+       size_t count;
+       ssize_t err;
+       u32 value;
+
+       err = mipi_dsi_create_packet(&packet, msg);
+       if (err < 0)
+               return err;
+
+       header = packet.header;
+
+       /* maximum FIFO depth is 1920 words */
+       if (packet.size > dsi->video_fifo_depth * 4)
+               return -ENOSPC;
+
+       /* reset underflow/overflow flags */
+       value = tegra_dsi_readl(dsi, DSI_STATUS);
+       if (value & (DSI_STATUS_UNDERFLOW | DSI_STATUS_OVERFLOW)) {
+               value = DSI_HOST_CONTROL_FIFO_RESET;
+               tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
+               usleep_range(10, 20);
+       }
+
+       value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
+       value |= DSI_POWER_CONTROL_ENABLE;
+       tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
+
+       usleep_range(5000, 10000);
+
+       value = DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST |
+               DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC;
+
+       if ((msg->flags & MIPI_DSI_MSG_USE_LPM) == 0)
+               value |= DSI_HOST_CONTROL_HS;
+
+       /*
+        * The host FIFO has a maximum of 64 words, so larger transmissions
+        * need to use the video FIFO.
+        */
+       if (packet.size > dsi->host_fifo_depth * 4)
+               value |= DSI_HOST_CONTROL_FIFO_SEL;
+
+       tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
+
+       /*
+        * For reads and messages with explicitly requested ACK, generate a
+        * BTA sequence after the transmission of the packet.
+        */
+       if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
+           (msg->rx_buf && msg->rx_len > 0)) {
+               value = tegra_dsi_readl(dsi, DSI_HOST_CONTROL);
+               value |= DSI_HOST_CONTROL_PKT_BTA;
+               tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
+       }
+
+       value = DSI_CONTROL_LANES(0) | DSI_CONTROL_HOST_ENABLE;
+       tegra_dsi_writel(dsi, value, DSI_CONTROL);
+
+       /* write packet header, ECC is generated by hardware */
+       value = header[2] << 16 | header[1] << 8 | header[0];
+       tegra_dsi_writel(dsi, value, DSI_WR_DATA);
+
+       /* write payload (if any) */
+       if (packet.payload_length > 0)
+               tegra_dsi_writesl(dsi, DSI_WR_DATA, packet.payload,
+                                 packet.payload_length);
+
+       err = tegra_dsi_transmit(dsi, 250);
+       if (err < 0)
+               return err;
+
+       if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
+           (msg->rx_buf && msg->rx_len > 0)) {
+               err = tegra_dsi_wait_for_response(dsi, 250);
+               if (err < 0)
+                       return err;
+
+               count = err;
+
+               value = tegra_dsi_readl(dsi, DSI_RD_DATA);
+               switch (value) {
+               case 0x84:
+                       /*
+                       dev_dbg(dsi->dev, "ACK\n");
+                       */
+                       break;
+
+               case 0x87:
+                       /*
+                       dev_dbg(dsi->dev, "ESCAPE\n");
+                       */
+                       break;
+
+               default:
+                       dev_err(dsi->dev, "unknown status: %08x\n", value);
+                       break;
+               }
+
+               if (count > 1) {
+                       err = tegra_dsi_read_response(dsi, msg, count);
+                       if (err < 0)
+                               dev_err(dsi->dev,
+                                       "failed to parse response: %zd\n",
+                                       err);
+                       else {
+                               /*
+                                * For read commands, return the number of
+                                * bytes returned by the peripheral.
+                                */
+                               count = err;
+                       }
+               }
+       } else {
+               /*
+                * For write commands, we have transmitted the 4-byte header
+                * plus the variable-length payload.
+                */
+               count = 4 + packet.payload_length;
+       }
+
+       return count;
+}
+
+static int tegra_dsi_ganged_setup(struct tegra_dsi *dsi)
+{
+       struct clk *parent;
+       int err;
+
+       /* make sure both DSI controllers share the same PLL */
+       parent = clk_get_parent(dsi->slave->clk);
+       if (!parent)
+               return -EINVAL;
+
+       err = clk_set_parent(parent, dsi->clk_parent);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
 static int tegra_dsi_host_attach(struct mipi_dsi_host *host,
                                 struct mipi_dsi_device *device)
 {
        struct tegra_dsi *dsi = host_to_tegra(host);
-       struct tegra_output *output = &dsi->output;
 
        dsi->flags = device->mode_flags;
        dsi->format = device->format;
        dsi->lanes = device->lanes;
 
-       output->panel = of_drm_find_panel(device->dev.of_node);
-       if (output->panel) {
-               if (output->connector.dev)
+       if (dsi->slave) {
+               int err;
+
+               dev_dbg(dsi->dev, "attaching dual-channel device %s\n",
+                       dev_name(&device->dev));
+
+               err = tegra_dsi_ganged_setup(dsi);
+               if (err < 0) {
+                       dev_err(dsi->dev, "failed to set up ganged mode: %d\n",
+                               err);
+                       return err;
+               }
+       }
+
+       /*
+        * Slaves don't have a panel associated with them, so they provide
+        * merely the second channel.
+        */
+       if (!dsi->master) {
+               struct tegra_output *output = &dsi->output;
+
+               output->panel = of_drm_find_panel(device->dev.of_node);
+               if (output->panel && output->connector.dev) {
+                       drm_panel_attach(output->panel, &output->connector);
                        drm_helper_hpd_irq_event(output->connector.dev);
+               }
        }
 
        return 0;
@@ -818,10 +1326,10 @@ static int tegra_dsi_host_detach(struct mipi_dsi_host *host,
        struct tegra_output *output = &dsi->output;
 
        if (output->panel && &device->dev == output->panel->dev) {
+               output->panel = NULL;
+
                if (output->connector.dev)
                        drm_helper_hpd_irq_event(output->connector.dev);
-
-               output->panel = NULL;
        }
 
        return 0;
@@ -830,8 +1338,29 @@ static int tegra_dsi_host_detach(struct mipi_dsi_host *host,
 static const struct mipi_dsi_host_ops tegra_dsi_host_ops = {
        .attach = tegra_dsi_host_attach,
        .detach = tegra_dsi_host_detach,
+       .transfer = tegra_dsi_host_transfer,
 };
 
+static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi)
+{
+       struct device_node *np;
+
+       np = of_parse_phandle(dsi->dev->of_node, "nvidia,ganged-mode", 0);
+       if (np) {
+               struct platform_device *gangster = of_find_device_by_node(np);
+
+               dsi->slave = platform_get_drvdata(gangster);
+               of_node_put(np);
+
+               if (!dsi->slave)
+                       return -EPROBE_DEFER;
+
+               dsi->slave->master = dsi;
+       }
+
+       return 0;
+}
+
 static int tegra_dsi_probe(struct platform_device *pdev)
 {
        struct tegra_dsi *dsi;
@@ -843,11 +1372,19 @@ static int tegra_dsi_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        dsi->output.dev = dsi->dev = &pdev->dev;
+       dsi->video_fifo_depth = 1920;
+       dsi->host_fifo_depth = 64;
+
+       err = tegra_dsi_ganged_probe(dsi);
+       if (err < 0)
+               return err;
 
        err = tegra_output_probe(&dsi->output);
        if (err < 0)
                return err;
 
+       dsi->output.connector.polled = DRM_CONNECTOR_POLL_HPD;
+
        /*
         * Assume these values by default. When a DSI peripheral driver
         * attaches to the DSI host, the parameters will be taken from
@@ -861,68 +1398,83 @@ static int tegra_dsi_probe(struct platform_device *pdev)
        if (IS_ERR(dsi->rst))
                return PTR_ERR(dsi->rst);
 
+       err = reset_control_deassert(dsi->rst);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to bring DSI out of reset: %d\n",
+                       err);
+               return err;
+       }
+
        dsi->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(dsi->clk)) {
                dev_err(&pdev->dev, "cannot get DSI clock\n");
-               return PTR_ERR(dsi->clk);
+               err = PTR_ERR(dsi->clk);
+               goto reset;
        }
 
        err = clk_prepare_enable(dsi->clk);
        if (err < 0) {
                dev_err(&pdev->dev, "cannot enable DSI clock\n");
-               return err;
+               goto reset;
        }
 
        dsi->clk_lp = devm_clk_get(&pdev->dev, "lp");
        if (IS_ERR(dsi->clk_lp)) {
                dev_err(&pdev->dev, "cannot get low-power clock\n");
-               return PTR_ERR(dsi->clk_lp);
+               err = PTR_ERR(dsi->clk_lp);
+               goto disable_clk;
        }
 
        err = clk_prepare_enable(dsi->clk_lp);
        if (err < 0) {
                dev_err(&pdev->dev, "cannot enable low-power clock\n");
-               return err;
+               goto disable_clk;
        }
 
        dsi->clk_parent = devm_clk_get(&pdev->dev, "parent");
        if (IS_ERR(dsi->clk_parent)) {
                dev_err(&pdev->dev, "cannot get parent clock\n");
-               return PTR_ERR(dsi->clk_parent);
-       }
-
-       err = clk_prepare_enable(dsi->clk_parent);
-       if (err < 0) {
-               dev_err(&pdev->dev, "cannot enable parent clock\n");
-               return err;
+               err = PTR_ERR(dsi->clk_parent);
+               goto disable_clk_lp;
        }
 
        dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi");
        if (IS_ERR(dsi->vdd)) {
                dev_err(&pdev->dev, "cannot get VDD supply\n");
-               return PTR_ERR(dsi->vdd);
+               err = PTR_ERR(dsi->vdd);
+               goto disable_clk_lp;
        }
 
        err = regulator_enable(dsi->vdd);
        if (err < 0) {
                dev_err(&pdev->dev, "cannot enable VDD supply\n");
-               return err;
+               goto disable_clk_lp;
        }
 
        err = tegra_dsi_setup_clocks(dsi);
        if (err < 0) {
                dev_err(&pdev->dev, "cannot setup clocks\n");
-               return err;
+               goto disable_vdd;
        }
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        dsi->regs = devm_ioremap_resource(&pdev->dev, regs);
-       if (IS_ERR(dsi->regs))
-               return PTR_ERR(dsi->regs);
+       if (IS_ERR(dsi->regs)) {
+               err = PTR_ERR(dsi->regs);
+               goto disable_vdd;
+       }
 
        dsi->mipi = tegra_mipi_request(&pdev->dev);
-       if (IS_ERR(dsi->mipi))
-               return PTR_ERR(dsi->mipi);
+       if (IS_ERR(dsi->mipi)) {
+               err = PTR_ERR(dsi->mipi);
+               goto disable_vdd;
+       }
+
+       err = tegra_dsi_pad_calibrate(dsi);
+       if (err < 0) {
+               dev_err(dsi->dev, "MIPI calibration failed: %d\n", err);
+               goto mipi_free;
+       }
 
        dsi->host.ops = &tegra_dsi_host_ops;
        dsi->host.dev = &pdev->dev;
@@ -930,7 +1482,7 @@ static int tegra_dsi_probe(struct platform_device *pdev)
        err = mipi_dsi_host_register(&dsi->host);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to register DSI host: %d\n", err);
-               return err;
+               goto mipi_free;
        }
 
        INIT_LIST_HEAD(&dsi->client.list);
@@ -941,12 +1493,26 @@ static int tegra_dsi_probe(struct platform_device *pdev)
        if (err < 0) {
                dev_err(&pdev->dev, "failed to register host1x client: %d\n",
                        err);
-               return err;
+               goto unregister;
        }
 
        platform_set_drvdata(pdev, dsi);
 
        return 0;
+
+unregister:
+       mipi_dsi_host_unregister(&dsi->host);
+mipi_free:
+       tegra_mipi_free(dsi->mipi);
+disable_vdd:
+       regulator_disable(dsi->vdd);
+disable_clk_lp:
+       clk_disable_unprepare(dsi->clk_lp);
+disable_clk:
+       clk_disable_unprepare(dsi->clk);
+reset:
+       reset_control_assert(dsi->rst);
+       return err;
 }
 
 static int tegra_dsi_remove(struct platform_device *pdev)
@@ -965,7 +1531,6 @@ static int tegra_dsi_remove(struct platform_device *pdev)
        tegra_mipi_free(dsi->mipi);
 
        regulator_disable(dsi->vdd);
-       clk_disable_unprepare(dsi->clk_parent);
        clk_disable_unprepare(dsi->clk_lp);
        clk_disable_unprepare(dsi->clk);
        reset_control_assert(dsi->rst);
index 5ce610d08d770afa2b9a26087a8c2055ec772edc..bad1006a51509da2868d83115245cb742ec29385 100644 (file)
 #define DSI_INT_STATUS                 0x0d
 #define DSI_INT_MASK                   0x0e
 #define DSI_HOST_CONTROL               0x0f
+#define DSI_HOST_CONTROL_FIFO_RESET    (1 << 21)
+#define DSI_HOST_CONTROL_CRC_RESET     (1 << 20)
+#define DSI_HOST_CONTROL_TX_TRIG_SOL   (0 << 12)
+#define DSI_HOST_CONTROL_TX_TRIG_FIFO  (1 << 12)
+#define DSI_HOST_CONTROL_TX_TRIG_HOST  (2 << 12)
 #define DSI_HOST_CONTROL_RAW           (1 << 6)
 #define DSI_HOST_CONTROL_HS            (1 << 5)
-#define DSI_HOST_CONTROL_BTA           (1 << 2)
+#define DSI_HOST_CONTROL_FIFO_SEL      (1 << 4)
+#define DSI_HOST_CONTROL_IMM_BTA       (1 << 3)
+#define DSI_HOST_CONTROL_PKT_BTA       (1 << 2)
 #define DSI_HOST_CONTROL_CS            (1 << 1)
 #define DSI_HOST_CONTROL_ECC           (1 << 0)
 #define DSI_CONTROL                    0x10
 #define DSI_SOL_DELAY                  0x11
 #define DSI_MAX_THRESHOLD              0x12
 #define DSI_TRIGGER                    0x13
+#define DSI_TRIGGER_HOST               (1 << 1)
+#define DSI_TRIGGER_VIDEO              (1 << 0)
 #define DSI_TX_CRC                     0x14
 #define DSI_STATUS                     0x15
 #define DSI_STATUS_IDLE                        (1 << 10)
+#define DSI_STATUS_UNDERFLOW           (1 <<  9)
+#define DSI_STATUS_OVERFLOW            (1 <<  8)
 #define DSI_INIT_SEQ_CONTROL           0x1a
 #define DSI_INIT_SEQ_DATA_0            0x1b
 #define DSI_INIT_SEQ_DATA_1            0x1c
 #define DSI_PAD_CONTROL_3              0x51
 #define DSI_PAD_CONTROL_4              0x52
 #define DSI_GANGED_MODE_CONTROL                0x53
+#define DSI_GANGED_MODE_CONTROL_ENABLE (1 << 0)
 #define DSI_GANGED_MODE_START          0x54
 #define DSI_GANGED_MODE_SIZE           0x55
 #define DSI_RAW_DATA_BYTE_COUNT                0x56
index 3513d12d5aa1447822a7ef57449799b1aff83df9..e9c715d892614853606c7563c4b335cb300d8c5f 100644 (file)
@@ -65,8 +65,12 @@ static void tegra_fb_destroy(struct drm_framebuffer *framebuffer)
        for (i = 0; i < fb->num_planes; i++) {
                struct tegra_bo *bo = fb->planes[i];
 
-               if (bo)
+               if (bo) {
+                       if (bo->pages && bo->vaddr)
+                               vunmap(bo->vaddr);
+
                        drm_gem_object_unreference_unlocked(&bo->gem);
+               }
        }
 
        drm_framebuffer_cleanup(framebuffer);
@@ -223,14 +227,16 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
        info = framebuffer_alloc(0, drm->dev);
        if (!info) {
                dev_err(drm->dev, "failed to allocate framebuffer info\n");
-               tegra_bo_free_object(&bo->gem);
+               drm_gem_object_unreference_unlocked(&bo->gem);
                return -ENOMEM;
        }
 
        fbdev->fb = tegra_fb_alloc(drm, &cmd, &bo, 1);
        if (IS_ERR(fbdev->fb)) {
-               dev_err(drm->dev, "failed to allocate DRM framebuffer\n");
                err = PTR_ERR(fbdev->fb);
+               dev_err(drm->dev, "failed to allocate DRM framebuffer: %d\n",
+                       err);
+               drm_gem_object_unreference_unlocked(&bo->gem);
                goto release;
        }
 
@@ -254,6 +260,16 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
        offset = info->var.xoffset * bytes_per_pixel +
                 info->var.yoffset * fb->pitches[0];
 
+       if (bo->pages) {
+               bo->vaddr = vmap(bo->pages, bo->num_pages, VM_MAP,
+                                pgprot_writecombine(PAGE_KERNEL));
+               if (!bo->vaddr) {
+                       dev_err(drm->dev, "failed to vmap() framebuffer\n");
+                       err = -ENOMEM;
+                       goto destroy;
+               }
+       }
+
        drm->mode_config.fb_base = (resource_size_t)bo->paddr;
        info->screen_base = (void __iomem *)bo->vaddr + offset;
        info->screen_size = size;
@@ -289,6 +305,11 @@ static struct tegra_fbdev *tegra_fbdev_create(struct drm_device *drm)
        return fbdev;
 }
 
+static void tegra_fbdev_free(struct tegra_fbdev *fbdev)
+{
+       kfree(fbdev);
+}
+
 static int tegra_fbdev_init(struct tegra_fbdev *fbdev,
                            unsigned int preferred_bpp,
                            unsigned int num_crtc,
@@ -299,19 +320,21 @@ static int tegra_fbdev_init(struct tegra_fbdev *fbdev,
 
        err = drm_fb_helper_init(drm, &fbdev->base, num_crtc, max_connectors);
        if (err < 0) {
-               dev_err(drm->dev, "failed to initialize DRM FB helper\n");
+               dev_err(drm->dev, "failed to initialize DRM FB helper: %d\n",
+                       err);
                return err;
        }
 
        err = drm_fb_helper_single_add_all_connectors(&fbdev->base);
        if (err < 0) {
-               dev_err(drm->dev, "failed to add connectors\n");
+               dev_err(drm->dev, "failed to add connectors: %d\n", err);
                goto fini;
        }
 
        err = drm_fb_helper_initial_config(&fbdev->base, preferred_bpp);
        if (err < 0) {
-               dev_err(drm->dev, "failed to set initial configuration\n");
+               dev_err(drm->dev, "failed to set initial configuration: %d\n",
+                       err);
                goto fini;
        }
 
@@ -322,7 +345,7 @@ fini:
        return err;
 }
 
-static void tegra_fbdev_free(struct tegra_fbdev *fbdev)
+static void tegra_fbdev_exit(struct tegra_fbdev *fbdev)
 {
        struct fb_info *info = fbdev->base.fbdev;
 
@@ -341,11 +364,11 @@ static void tegra_fbdev_free(struct tegra_fbdev *fbdev)
 
        if (fbdev->fb) {
                drm_framebuffer_unregister_private(&fbdev->fb->base);
-               tegra_fb_destroy(&fbdev->fb->base);
+               drm_framebuffer_remove(&fbdev->fb->base);
        }
 
        drm_fb_helper_fini(&fbdev->base);
-       kfree(fbdev);
+       tegra_fbdev_free(fbdev);
 }
 
 void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev)
@@ -393,6 +416,15 @@ int tegra_drm_fb_prepare(struct drm_device *drm)
        return 0;
 }
 
+void tegra_drm_fb_free(struct drm_device *drm)
+{
+#ifdef CONFIG_DRM_TEGRA_FBDEV
+       struct tegra_drm *tegra = drm->dev_private;
+
+       tegra_fbdev_free(tegra->fbdev);
+#endif
+}
+
 int tegra_drm_fb_init(struct drm_device *drm)
 {
 #ifdef CONFIG_DRM_TEGRA_FBDEV
@@ -413,6 +445,6 @@ void tegra_drm_fb_exit(struct drm_device *drm)
 #ifdef CONFIG_DRM_TEGRA_FBDEV
        struct tegra_drm *tegra = drm->dev_private;
 
-       tegra_fbdev_free(tegra->fbdev);
+       tegra_fbdev_exit(tegra->fbdev);
 #endif
 }
index ce023fa3e8ae14bdfc3557295d69a7d8d12f9cd3..da32086cbeaf28bbe0c0528eeeac4c0bb9fcb326 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/dma-buf.h>
+#include <linux/iommu.h>
 #include <drm/tegra_drm.h>
 
 #include "drm.h"
@@ -91,13 +92,90 @@ static const struct host1x_bo_ops tegra_bo_ops = {
        .kunmap = tegra_bo_kunmap,
 };
 
-static void tegra_bo_destroy(struct drm_device *drm, struct tegra_bo *bo)
+/*
+ * A generic iommu_map_sg() function is being reviewed and will hopefully be
+ * merged soon. At that point this function can be dropped in favour of the
+ * one provided by the IOMMU API.
+ */
+static ssize_t __iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+                             struct scatterlist *sg, unsigned int nents,
+                             int prot)
 {
-       dma_free_writecombine(drm->dev, bo->gem.size, bo->vaddr, bo->paddr);
+       struct scatterlist *s;
+       size_t offset = 0;
+       unsigned int i;
+       int err;
+
+       for_each_sg(sg, s, nents, i) {
+               phys_addr_t phys = page_to_phys(sg_page(s));
+               size_t length = s->offset + s->length;
+
+               err = iommu_map(domain, iova + offset, phys, length, prot);
+               if (err < 0) {
+                       iommu_unmap(domain, iova, offset);
+                       return err;
+               }
+
+               offset += length;
+       }
+
+       return offset;
 }
 
-struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size,
-                                unsigned long flags)
+static int tegra_bo_iommu_map(struct tegra_drm *tegra, struct tegra_bo *bo)
+{
+       int prot = IOMMU_READ | IOMMU_WRITE;
+       ssize_t err;
+
+       if (bo->mm)
+               return -EBUSY;
+
+       bo->mm = kzalloc(sizeof(*bo->mm), GFP_KERNEL);
+       if (!bo->mm)
+               return -ENOMEM;
+
+       err = drm_mm_insert_node_generic(&tegra->mm, bo->mm, bo->gem.size,
+                                        PAGE_SIZE, 0, 0, 0);
+       if (err < 0) {
+               dev_err(tegra->drm->dev, "out of I/O virtual memory: %zd\n",
+                       err);
+               goto free;
+       }
+
+       bo->paddr = bo->mm->start;
+
+       err = __iommu_map_sg(tegra->domain, bo->paddr, bo->sgt->sgl,
+                            bo->sgt->nents, prot);
+       if (err < 0) {
+               dev_err(tegra->drm->dev, "failed to map buffer: %zd\n", err);
+               goto remove;
+       }
+
+       bo->size = err;
+
+       return 0;
+
+remove:
+       drm_mm_remove_node(bo->mm);
+free:
+       kfree(bo->mm);
+       return err;
+}
+
+static int tegra_bo_iommu_unmap(struct tegra_drm *tegra, struct tegra_bo *bo)
+{
+       if (!bo->mm)
+               return 0;
+
+       iommu_unmap(tegra->domain, bo->paddr, bo->size);
+       drm_mm_remove_node(bo->mm);
+       kfree(bo->mm);
+
+       return 0;
+}
+
+static struct tegra_bo *tegra_bo_alloc_object(struct drm_device *drm,
+                                             size_t size)
 {
        struct tegra_bo *bo;
        int err;
@@ -109,22 +187,96 @@ struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size,
        host1x_bo_init(&bo->base, &tegra_bo_ops);
        size = round_up(size, PAGE_SIZE);
 
-       bo->vaddr = dma_alloc_writecombine(drm->dev, size, &bo->paddr,
-                                          GFP_KERNEL | __GFP_NOWARN);
-       if (!bo->vaddr) {
-               dev_err(drm->dev, "failed to allocate buffer with size %u\n",
-                       size);
-               err = -ENOMEM;
-               goto err_dma;
-       }
-
        err = drm_gem_object_init(drm, &bo->gem, size);
-       if (err)
-               goto err_init;
+       if (err < 0)
+               goto free;
 
        err = drm_gem_create_mmap_offset(&bo->gem);
-       if (err)
-               goto err_mmap;
+       if (err < 0)
+               goto release;
+
+       return bo;
+
+release:
+       drm_gem_object_release(&bo->gem);
+free:
+       kfree(bo);
+       return ERR_PTR(err);
+}
+
+static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo)
+{
+       if (bo->pages) {
+               drm_gem_put_pages(&bo->gem, bo->pages, true, true);
+               sg_free_table(bo->sgt);
+               kfree(bo->sgt);
+       } else if (bo->vaddr) {
+               dma_free_writecombine(drm->dev, bo->gem.size, bo->vaddr,
+                                     bo->paddr);
+       }
+}
+
+static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo,
+                             size_t size)
+{
+       bo->pages = drm_gem_get_pages(&bo->gem);
+       if (IS_ERR(bo->pages))
+               return PTR_ERR(bo->pages);
+
+       bo->num_pages = size >> PAGE_SHIFT;
+
+       bo->sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages);
+       if (IS_ERR(bo->sgt)) {
+               drm_gem_put_pages(&bo->gem, bo->pages, false, false);
+               return PTR_ERR(bo->sgt);
+       }
+
+       return 0;
+}
+
+static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo,
+                         size_t size)
+{
+       struct tegra_drm *tegra = drm->dev_private;
+       int err;
+
+       if (tegra->domain) {
+               err = tegra_bo_get_pages(drm, bo, size);
+               if (err < 0)
+                       return err;
+
+               err = tegra_bo_iommu_map(tegra, bo);
+               if (err < 0) {
+                       tegra_bo_free(drm, bo);
+                       return err;
+               }
+       } else {
+               bo->vaddr = dma_alloc_writecombine(drm->dev, size, &bo->paddr,
+                                                  GFP_KERNEL | __GFP_NOWARN);
+               if (!bo->vaddr) {
+                       dev_err(drm->dev,
+                               "failed to allocate buffer of size %zu\n",
+                               size);
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+struct tegra_bo *tegra_bo_create(struct drm_device *drm, size_t size,
+                                unsigned long flags)
+{
+       struct tegra_bo *bo;
+       int err;
+
+       bo = tegra_bo_alloc_object(drm, size);
+       if (IS_ERR(bo))
+               return bo;
+
+       err = tegra_bo_alloc(drm, bo, size);
+       if (err < 0)
+               goto release;
 
        if (flags & DRM_TEGRA_GEM_CREATE_TILED)
                bo->tiling.mode = TEGRA_BO_TILING_MODE_TILED;
@@ -134,69 +286,52 @@ struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size,
 
        return bo;
 
-err_mmap:
+release:
        drm_gem_object_release(&bo->gem);
-err_init:
-       tegra_bo_destroy(drm, bo);
-err_dma:
        kfree(bo);
-
        return ERR_PTR(err);
 }
 
 struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file,
                                             struct drm_device *drm,
-                                            unsigned int size,
+                                            size_t size,
                                             unsigned long flags,
-                                            unsigned int *handle)
+                                            u32 *handle)
 {
        struct tegra_bo *bo;
-       int ret;
+       int err;
 
        bo = tegra_bo_create(drm, size, flags);
        if (IS_ERR(bo))
                return bo;
 
-       ret = drm_gem_handle_create(file, &bo->gem, handle);
-       if (ret)
-               goto err;
+       err = drm_gem_handle_create(file, &bo->gem, handle);
+       if (err) {
+               tegra_bo_free_object(&bo->gem);
+               return ERR_PTR(err);
+       }
 
        drm_gem_object_unreference_unlocked(&bo->gem);
 
        return bo;
-
-err:
-       tegra_bo_free_object(&bo->gem);
-       return ERR_PTR(ret);
 }
 
 static struct tegra_bo *tegra_bo_import(struct drm_device *drm,
                                        struct dma_buf *buf)
 {
+       struct tegra_drm *tegra = drm->dev_private;
        struct dma_buf_attachment *attach;
        struct tegra_bo *bo;
-       ssize_t size;
        int err;
 
-       bo = kzalloc(sizeof(*bo), GFP_KERNEL);
-       if (!bo)
-               return ERR_PTR(-ENOMEM);
-
-       host1x_bo_init(&bo->base, &tegra_bo_ops);
-       size = round_up(buf->size, PAGE_SIZE);
-
-       err = drm_gem_object_init(drm, &bo->gem, size);
-       if (err < 0)
-               goto free;
-
-       err = drm_gem_create_mmap_offset(&bo->gem);
-       if (err < 0)
-               goto release;
+       bo = tegra_bo_alloc_object(drm, buf->size);
+       if (IS_ERR(bo))
+               return bo;
 
        attach = dma_buf_attach(buf, drm->dev);
        if (IS_ERR(attach)) {
                err = PTR_ERR(attach);
-               goto free_mmap;
+               goto free;
        }
 
        get_dma_buf(buf);
@@ -212,12 +347,19 @@ static struct tegra_bo *tegra_bo_import(struct drm_device *drm,
                goto detach;
        }
 
-       if (bo->sgt->nents > 1) {
-               err = -EINVAL;
-               goto detach;
+       if (tegra->domain) {
+               err = tegra_bo_iommu_map(tegra, bo);
+               if (err < 0)
+                       goto detach;
+       } else {
+               if (bo->sgt->nents > 1) {
+                       err = -EINVAL;
+                       goto detach;
+               }
+
+               bo->paddr = sg_dma_address(bo->sgt->sgl);
        }
 
-       bo->paddr = sg_dma_address(bo->sgt->sgl);
        bo->gem.import_attach = attach;
 
        return bo;
@@ -228,47 +370,41 @@ detach:
 
        dma_buf_detach(buf, attach);
        dma_buf_put(buf);
-free_mmap:
-       drm_gem_free_mmap_offset(&bo->gem);
-release:
-       drm_gem_object_release(&bo->gem);
 free:
+       drm_gem_object_release(&bo->gem);
        kfree(bo);
-
        return ERR_PTR(err);
 }
 
 void tegra_bo_free_object(struct drm_gem_object *gem)
 {
+       struct tegra_drm *tegra = gem->dev->dev_private;
        struct tegra_bo *bo = to_tegra_bo(gem);
 
+       if (tegra->domain)
+               tegra_bo_iommu_unmap(tegra, bo);
+
        if (gem->import_attach) {
                dma_buf_unmap_attachment(gem->import_attach, bo->sgt,
                                         DMA_TO_DEVICE);
                drm_prime_gem_destroy(gem, NULL);
        } else {
-               tegra_bo_destroy(gem->dev, bo);
+               tegra_bo_free(gem->dev, bo);
        }
 
-       drm_gem_free_mmap_offset(gem);
        drm_gem_object_release(gem);
-
        kfree(bo);
 }
 
 int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm,
                         struct drm_mode_create_dumb *args)
 {
-       int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+       unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
        struct tegra_drm *tegra = drm->dev_private;
        struct tegra_bo *bo;
 
-       min_pitch = round_up(min_pitch, tegra->pitch_align);
-       if (args->pitch < min_pitch)
-               args->pitch = min_pitch;
-
-       if (args->size < args->pitch * args->height)
-               args->size = args->pitch * args->height;
+       args->pitch = round_up(min_pitch, tegra->pitch_align);
+       args->size = args->pitch * args->height;
 
        bo = tegra_bo_create_with_handle(file, drm, args->size, 0,
                                         &args->handle);
@@ -279,7 +415,7 @@ int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm,
 }
 
 int tegra_bo_dumb_map_offset(struct drm_file *file, struct drm_device *drm,
-                            uint32_t handle, uint64_t *offset)
+                            u32 handle, u64 *offset)
 {
        struct drm_gem_object *gem;
        struct tegra_bo *bo;
@@ -304,7 +440,38 @@ int tegra_bo_dumb_map_offset(struct drm_file *file, struct drm_device *drm,
        return 0;
 }
 
+static int tegra_bo_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       struct drm_gem_object *gem = vma->vm_private_data;
+       struct tegra_bo *bo = to_tegra_bo(gem);
+       struct page *page;
+       pgoff_t offset;
+       int err;
+
+       if (!bo->pages)
+               return VM_FAULT_SIGBUS;
+
+       offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> PAGE_SHIFT;
+       page = bo->pages[offset];
+
+       err = vm_insert_page(vma, (unsigned long)vmf->virtual_address, page);
+       switch (err) {
+       case -EAGAIN:
+       case 0:
+       case -ERESTARTSYS:
+       case -EINTR:
+       case -EBUSY:
+               return VM_FAULT_NOPAGE;
+
+       case -ENOMEM:
+               return VM_FAULT_OOM;
+       }
+
+       return VM_FAULT_SIGBUS;
+}
+
 const struct vm_operations_struct tegra_bo_vm_ops = {
+       .fault = tegra_bo_fault,
        .open = drm_gem_vm_open,
        .close = drm_gem_vm_close,
 };
@@ -322,12 +489,30 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma)
        gem = vma->vm_private_data;
        bo = to_tegra_bo(gem);
 
-       ret = remap_pfn_range(vma, vma->vm_start, bo->paddr >> PAGE_SHIFT,
-                             vma->vm_end - vma->vm_start, vma->vm_page_prot);
-       if (ret)
-               drm_gem_vm_close(vma);
+       if (!bo->pages) {
+               unsigned long vm_pgoff = vma->vm_pgoff;
+
+               vma->vm_flags &= ~VM_PFNMAP;
+               vma->vm_pgoff = 0;
+
+               ret = dma_mmap_writecombine(gem->dev->dev, vma, bo->vaddr,
+                                           bo->paddr, gem->size);
+               if (ret) {
+                       drm_gem_vm_close(vma);
+                       return ret;
+               }
+
+               vma->vm_pgoff = vm_pgoff;
+       } else {
+               pgprot_t prot = vm_get_page_prot(vma->vm_flags);
+
+               vma->vm_flags |= VM_MIXEDMAP;
+               vma->vm_flags &= ~VM_PFNMAP;
 
-       return ret;
+               vma->vm_page_prot = pgprot_writecombine(prot);
+       }
+
+       return 0;
 }
 
 static struct sg_table *
@@ -342,21 +527,44 @@ tegra_gem_prime_map_dma_buf(struct dma_buf_attachment *attach,
        if (!sgt)
                return NULL;
 
-       if (sg_alloc_table(sgt, 1, GFP_KERNEL)) {
-               kfree(sgt);
-               return NULL;
-       }
+       if (bo->pages) {
+               struct scatterlist *sg;
+               unsigned int i;
 
-       sg_dma_address(sgt->sgl) = bo->paddr;
-       sg_dma_len(sgt->sgl) = gem->size;
+               if (sg_alloc_table(sgt, bo->num_pages, GFP_KERNEL))
+                       goto free;
+
+               for_each_sg(sgt->sgl, sg, bo->num_pages, i)
+                       sg_set_page(sg, bo->pages[i], PAGE_SIZE, 0);
+
+               if (dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir) == 0)
+                       goto free;
+       } else {
+               if (sg_alloc_table(sgt, 1, GFP_KERNEL))
+                       goto free;
+
+               sg_dma_address(sgt->sgl) = bo->paddr;
+               sg_dma_len(sgt->sgl) = gem->size;
+       }
 
        return sgt;
+
+free:
+       sg_free_table(sgt);
+       kfree(sgt);
+       return NULL;
 }
 
 static void tegra_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach,
                                          struct sg_table *sgt,
                                          enum dma_data_direction dir)
 {
+       struct drm_gem_object *gem = attach->dmabuf->priv;
+       struct tegra_bo *bo = to_tegra_bo(gem);
+
+       if (bo->pages)
+               dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir);
+
        sg_free_table(sgt);
        kfree(sgt);
 }
index 6538b56780c2a916e817d44080e952c37bba8a89..6c5f12ac0087a0b8baf538f435d244f2ffa1537b 100644 (file)
@@ -38,6 +38,12 @@ struct tegra_bo {
        dma_addr_t paddr;
        void *vaddr;
 
+       struct drm_mm_node *mm;
+       unsigned long num_pages;
+       struct page **pages;
+       /* size of IOMMU mapping */
+       size_t size;
+
        struct tegra_bo_tiling tiling;
 };
 
@@ -46,18 +52,18 @@ static inline struct tegra_bo *to_tegra_bo(struct drm_gem_object *gem)
        return container_of(gem, struct tegra_bo, gem);
 }
 
-struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size,
+struct tegra_bo *tegra_bo_create(struct drm_device *drm, size_t size,
                                 unsigned long flags);
 struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file,
                                             struct drm_device *drm,
-                                            unsigned int size,
+                                            size_t size,
                                             unsigned long flags,
-                                            unsigned int *handle);
+                                            u32 *handle);
 void tegra_bo_free_object(struct drm_gem_object *gem);
 int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm,
                         struct drm_mode_create_dumb *args);
 int tegra_bo_dumb_map_offset(struct drm_file *file, struct drm_device *drm,
-                            uint32_t handle, uint64_t *offset);
+                            u32 handle, u64 *offset);
 
 int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma);
 
index 0c67d7eebc94876d645fe0827485bdc13a998035..6a5c7b81fbc5d6453c7b96ab57339400504a913c 100644 (file)
@@ -157,22 +157,18 @@ static bool tegra_encoder_mode_fixup(struct drm_encoder *encoder,
 
 static void tegra_encoder_prepare(struct drm_encoder *encoder)
 {
+       tegra_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
 }
 
 static void tegra_encoder_commit(struct drm_encoder *encoder)
 {
+       tegra_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
 }
 
 static void tegra_encoder_mode_set(struct drm_encoder *encoder,
                                   struct drm_display_mode *mode,
                                   struct drm_display_mode *adjusted)
 {
-       struct tegra_output *output = encoder_to_output(encoder);
-       int err;
-
-       err = tegra_output_enable(output);
-       if (err < 0)
-               dev_err(encoder->dev->dev, "tegra_output_enable(): %d\n", err);
 }
 
 static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
@@ -187,7 +183,8 @@ static irqreturn_t hpd_irq(int irq, void *data)
 {
        struct tegra_output *output = data;
 
-       drm_helper_hpd_irq_event(output->connector.dev);
+       if (output->connector.dev)
+               drm_helper_hpd_irq_event(output->connector.dev);
 
        return IRQ_HANDLED;
 }
@@ -259,6 +256,13 @@ int tegra_output_probe(struct tegra_output *output)
                }
 
                output->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
+               /*
+                * Disable the interrupt until the connector has been
+                * initialized to avoid a race in the hotplug interrupt
+                * handler.
+                */
+               disable_irq(output->hpd_irq);
        }
 
        return 0;
@@ -324,10 +328,27 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
 
        output->encoder.possible_crtcs = 0x3;
 
+       /*
+        * The connector is now registered and ready to receive hotplug events
+        * so the hotplug interrupt can be enabled.
+        */
+       if (gpio_is_valid(output->hpd_gpio))
+               enable_irq(output->hpd_irq);
+
        return 0;
 }
 
 int tegra_output_exit(struct tegra_output *output)
 {
+       /*
+        * The connector is going away, so the interrupt must be disabled to
+        * prevent the hotplug interrupt handler from potentially crashing.
+        */
+       if (gpio_is_valid(output->hpd_gpio))
+               disable_irq(output->hpd_irq);
+
+       if (output->panel)
+               drm_panel_detach(output->panel);
+
        return 0;
 }
index 29ec98baffd19faf55df10896bbca4953db4de17..c73588483be02e0ba97e52017ff972e59841c4d7 100644 (file)
@@ -665,12 +665,8 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev)
        tilcdc_crtc->dpms = DRM_MODE_DPMS_OFF;
        init_waitqueue_head(&tilcdc_crtc->frame_done_wq);
 
-       ret = drm_flip_work_init(&tilcdc_crtc->unref_work, 16,
+       drm_flip_work_init(&tilcdc_crtc->unref_work,
                        "unref", unref_worker);
-       if (ret) {
-               dev_err(dev->dev, "could not allocate unref FIFO\n");
-               goto fail;
-       }
 
        ret = drm_crtc_init(dev, crtc, &tilcdc_crtc_funcs);
        if (ret < 0)
index 79a34cbd29f5260df24da1ae86d460e1a0df3c6f..d56d3f8b8d6bc676a4e770b3e2279812b56d0229 100644 (file)
@@ -58,8 +58,7 @@ static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev,
 static void tilcdc_fb_output_poll_changed(struct drm_device *dev)
 {
        struct tilcdc_drm_private *priv = dev->dev_private;
-       if (priv->fbdev)
-               drm_fbdev_cma_hotplug_event(priv->fbdev);
+       drm_fbdev_cma_hotplug_event(priv->fbdev);
 }
 
 static const struct drm_mode_config_funcs mode_config_funcs = {
index 964387fc5c8f860544704ae3ce21d50084448361..aa0bd054d3e95c148f63072a39f82059ba2b366c 100644 (file)
@@ -55,6 +55,7 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
        struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
        struct drm_mm *mm = &rman->mm;
        struct drm_mm_node *node = NULL;
+       enum drm_mm_search_flags sflags = DRM_MM_SEARCH_BEST;
        enum drm_mm_allocator_flags aflags = DRM_MM_CREATE_DEFAULT;
        unsigned long lpfn;
        int ret;
@@ -67,15 +68,16 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
        if (!node)
                return -ENOMEM;
 
-       if (place->flags & TTM_PL_FLAG_TOPDOWN)
+       if (place->flags & TTM_PL_FLAG_TOPDOWN) {
+               sflags = DRM_MM_SEARCH_BELOW;
                aflags = DRM_MM_CREATE_TOP;
+       }
 
        spin_lock(&rman->lock);
        ret = drm_mm_insert_node_in_range_generic(mm, node, mem->num_pages,
                                          mem->page_alignment, 0,
                                          place->fpfn, lpfn,
-                                         DRM_MM_SEARCH_BEST,
-                                         aflags);
+                                         sflags, aflags);
        spin_unlock(&rman->lock);
 
        if (unlikely(ret)) {
index 09874d695188067dca03540efd5b2f135a75b913..025c429050c06c4079f5b471128e499463abc753 100644 (file)
@@ -297,11 +297,12 @@ static void ttm_pool_update_free_locked(struct ttm_page_pool *pool,
  *
  * @pool: to free the pages from
  * @free_all: If set to true will free all pages in pool
- * @gfp: GFP flags.
+ * @use_static: Safe to use static buffer
  **/
 static int ttm_page_pool_free(struct ttm_page_pool *pool, unsigned nr_free,
-                             gfp_t gfp)
+                             bool use_static)
 {
+       static struct page *static_buf[NUM_PAGES_TO_ALLOC];
        unsigned long irq_flags;
        struct page *p;
        struct page **pages_to_free;
@@ -311,7 +312,11 @@ static int ttm_page_pool_free(struct ttm_page_pool *pool, unsigned nr_free,
        if (NUM_PAGES_TO_ALLOC < nr_free)
                npages_to_free = NUM_PAGES_TO_ALLOC;
 
-       pages_to_free = kmalloc(npages_to_free * sizeof(struct page *), gfp);
+       if (use_static)
+               pages_to_free = static_buf;
+       else
+               pages_to_free = kmalloc(npages_to_free * sizeof(struct page *),
+                                       GFP_KERNEL);
        if (!pages_to_free) {
                pr_err("Failed to allocate memory for pool free operation\n");
                return 0;
@@ -374,7 +379,8 @@ restart:
        if (freed_pages)
                ttm_pages_put(pages_to_free, freed_pages);
 out:
-       kfree(pages_to_free);
+       if (pages_to_free != static_buf)
+               kfree(pages_to_free);
        return nr_free;
 }
 
@@ -383,8 +389,6 @@ out:
  *
  * XXX: (dchinner) Deadlock warning!
  *
- * We need to pass sc->gfp_mask to ttm_page_pool_free().
- *
  * This code is crying out for a shrinker per pool....
  */
 static unsigned long
@@ -407,8 +411,8 @@ ttm_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
                if (shrink_pages == 0)
                        break;
                pool = &_manager->pools[(i + pool_offset)%NUM_POOLS];
-               shrink_pages = ttm_page_pool_free(pool, nr_free,
-                                                 sc->gfp_mask);
+               /* OK to use static buffer since global mutex is held. */
+               shrink_pages = ttm_page_pool_free(pool, nr_free, true);
                freed += nr_free - shrink_pages;
        }
        mutex_unlock(&lock);
@@ -710,7 +714,7 @@ static void ttm_put_pages(struct page **pages, unsigned npages, int flags,
        }
        spin_unlock_irqrestore(&pool->lock, irq_flags);
        if (npages)
-               ttm_page_pool_free(pool, npages, GFP_KERNEL);
+               ttm_page_pool_free(pool, npages, false);
 }
 
 /*
@@ -849,9 +853,9 @@ void ttm_page_alloc_fini(void)
        pr_info("Finalizing pool allocator\n");
        ttm_pool_mm_shrink_fini(_manager);
 
+       /* OK to use static buffer since global mutex is no longer used. */
        for (i = 0; i < NUM_POOLS; ++i)
-               ttm_page_pool_free(&_manager->pools[i], FREE_ALL_PAGES,
-                                  GFP_KERNEL);
+               ttm_page_pool_free(&_manager->pools[i], FREE_ALL_PAGES, true);
 
        kobject_put(&_manager->kobj);
        _manager = NULL;
index c96db433f8af834398f6496da9498db98013a7c7..01e1d27eb078396cd97dc2f3a51cbda8dec95a9f 100644 (file)
@@ -411,11 +411,12 @@ static void ttm_dma_page_put(struct dma_pool *pool, struct dma_page *d_page)
  *
  * @pool: to free the pages from
  * @nr_free: If set to true will free all pages in pool
- * @gfp: GFP flags.
+ * @use_static: Safe to use static buffer
  **/
 static unsigned ttm_dma_page_pool_free(struct dma_pool *pool, unsigned nr_free,
-                                      gfp_t gfp)
+                                      bool use_static)
 {
+       static struct page *static_buf[NUM_PAGES_TO_ALLOC];
        unsigned long irq_flags;
        struct dma_page *dma_p, *tmp;
        struct page **pages_to_free;
@@ -432,7 +433,11 @@ static unsigned ttm_dma_page_pool_free(struct dma_pool *pool, unsigned nr_free,
                         npages_to_free, nr_free);
        }
 #endif
-       pages_to_free = kmalloc(npages_to_free * sizeof(struct page *), gfp);
+       if (use_static)
+               pages_to_free = static_buf;
+       else
+               pages_to_free = kmalloc(npages_to_free * sizeof(struct page *),
+                                       GFP_KERNEL);
 
        if (!pages_to_free) {
                pr_err("%s: Failed to allocate memory for pool free operation\n",
@@ -502,7 +507,8 @@ restart:
        if (freed_pages)
                ttm_dma_pages_put(pool, &d_pages, pages_to_free, freed_pages);
 out:
-       kfree(pages_to_free);
+       if (pages_to_free != static_buf)
+               kfree(pages_to_free);
        return nr_free;
 }
 
@@ -531,7 +537,8 @@ static void ttm_dma_free_pool(struct device *dev, enum pool_type type)
                if (pool->type != type)
                        continue;
                /* Takes a spinlock.. */
-               ttm_dma_page_pool_free(pool, FREE_ALL_PAGES, GFP_KERNEL);
+               /* OK to use static buffer since global mutex is held. */
+               ttm_dma_page_pool_free(pool, FREE_ALL_PAGES, true);
                WARN_ON(((pool->npages_in_use + pool->npages_free) != 0));
                /* This code path is called after _all_ references to the
                 * struct device has been dropped - so nobody should be
@@ -986,7 +993,7 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev)
 
        /* shrink pool if necessary (only on !is_cached pools)*/
        if (npages)
-               ttm_dma_page_pool_free(pool, npages, GFP_KERNEL);
+               ttm_dma_page_pool_free(pool, npages, false);
        ttm->state = tt_unpopulated;
 }
 EXPORT_SYMBOL_GPL(ttm_dma_unpopulate);
@@ -996,8 +1003,6 @@ EXPORT_SYMBOL_GPL(ttm_dma_unpopulate);
  *
  * XXX: (dchinner) Deadlock warning!
  *
- * We need to pass sc->gfp_mask to ttm_dma_page_pool_free().
- *
  * I'm getting sadder as I hear more pathetical whimpers about needing per-pool
  * shrinkers
  */
@@ -1030,8 +1035,8 @@ ttm_dma_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
                if (++idx < pool_offset)
                        continue;
                nr_free = shrink_pages;
-               shrink_pages = ttm_dma_page_pool_free(p->pool, nr_free,
-                                                     sc->gfp_mask);
+               /* OK to use static buffer since global mutex is held. */
+               shrink_pages = ttm_dma_page_pool_free(p->pool, nr_free, true);
                freed += nr_free - shrink_pages;
 
                pr_debug("%s: (%s:%d) Asked to shrink %d, have %d more to go\n",
index 05c7481bfd40d3ff8b49e7ffd6676d5a37eae600..195bcac0b6c8d9e429964d5e942ad1b7a2d9d74d 100644 (file)
@@ -1,6 +1,6 @@
 
 ccflags-y := -Iinclude/drm
 
-udl-y := udl_drv.o udl_modeset.o udl_connector.o udl_encoder.o udl_main.o udl_fb.o udl_transfer.o udl_gem.o
+udl-y := udl_drv.o udl_modeset.o udl_connector.o udl_encoder.o udl_main.o udl_fb.o udl_transfer.o udl_gem.o udl_dmabuf.o
 
 obj-$(CONFIG_DRM_UDL) := udl.o
diff --git a/drivers/gpu/drm/udl/udl_dmabuf.c b/drivers/gpu/drm/udl/udl_dmabuf.c
new file mode 100644 (file)
index 0000000..ac8a66b
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * udl_dmabuf.c
+ *
+ * Copyright (c) 2014 The Chromium OS Authors
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <drm/drmP.h>
+#include "udl_drv.h"
+#include <linux/shmem_fs.h>
+#include <linux/dma-buf.h>
+
+struct udl_drm_dmabuf_attachment {
+       struct sg_table sgt;
+       enum dma_data_direction dir;
+       bool is_mapped;
+};
+
+static int udl_attach_dma_buf(struct dma_buf *dmabuf,
+                             struct device *dev,
+                             struct dma_buf_attachment *attach)
+{
+       struct udl_drm_dmabuf_attachment *udl_attach;
+
+       DRM_DEBUG_PRIME("[DEV:%s] size:%zd\n", dev_name(attach->dev),
+                       attach->dmabuf->size);
+
+       udl_attach = kzalloc(sizeof(*udl_attach), GFP_KERNEL);
+       if (!udl_attach)
+               return -ENOMEM;
+
+       udl_attach->dir = DMA_NONE;
+       attach->priv = udl_attach;
+
+       return 0;
+}
+
+static void udl_detach_dma_buf(struct dma_buf *dmabuf,
+                              struct dma_buf_attachment *attach)
+{
+       struct udl_drm_dmabuf_attachment *udl_attach = attach->priv;
+       struct sg_table *sgt;
+
+       if (!udl_attach)
+               return;
+
+       DRM_DEBUG_PRIME("[DEV:%s] size:%zd\n", dev_name(attach->dev),
+                       attach->dmabuf->size);
+
+       sgt = &udl_attach->sgt;
+
+       if (udl_attach->dir != DMA_NONE)
+               dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents,
+                               udl_attach->dir);
+
+       sg_free_table(sgt);
+       kfree(udl_attach);
+       attach->priv = NULL;
+}
+
+static struct sg_table *udl_map_dma_buf(struct dma_buf_attachment *attach,
+                                       enum dma_data_direction dir)
+{
+       struct udl_drm_dmabuf_attachment *udl_attach = attach->priv;
+       struct udl_gem_object *obj = to_udl_bo(attach->dmabuf->priv);
+       struct drm_device *dev = obj->base.dev;
+       struct scatterlist *rd, *wr;
+       struct sg_table *sgt = NULL;
+       unsigned int i;
+       int page_count;
+       int nents, ret;
+
+       DRM_DEBUG_PRIME("[DEV:%s] size:%zd dir=%d\n", dev_name(attach->dev),
+                       attach->dmabuf->size, dir);
+
+       /* just return current sgt if already requested. */
+       if (udl_attach->dir == dir && udl_attach->is_mapped)
+               return &udl_attach->sgt;
+
+       if (!obj->pages) {
+               ret = udl_gem_get_pages(obj);
+               if (ret) {
+                       DRM_ERROR("failed to map pages.\n");
+                       return ERR_PTR(ret);
+               }
+       }
+
+       page_count = obj->base.size / PAGE_SIZE;
+       obj->sg = drm_prime_pages_to_sg(obj->pages, page_count);
+       if (IS_ERR(obj->sg)) {
+               DRM_ERROR("failed to allocate sgt.\n");
+               return ERR_CAST(obj->sg);
+       }
+
+       sgt = &udl_attach->sgt;
+
+       ret = sg_alloc_table(sgt, obj->sg->orig_nents, GFP_KERNEL);
+       if (ret) {
+               DRM_ERROR("failed to alloc sgt.\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       mutex_lock(&dev->struct_mutex);
+
+       rd = obj->sg->sgl;
+       wr = sgt->sgl;
+       for (i = 0; i < sgt->orig_nents; ++i) {
+               sg_set_page(wr, sg_page(rd), rd->length, rd->offset);
+               rd = sg_next(rd);
+               wr = sg_next(wr);
+       }
+
+       if (dir != DMA_NONE) {
+               nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir);
+               if (!nents) {
+                       DRM_ERROR("failed to map sgl with iommu.\n");
+                       sg_free_table(sgt);
+                       sgt = ERR_PTR(-EIO);
+                       goto err_unlock;
+               }
+       }
+
+       udl_attach->is_mapped = true;
+       udl_attach->dir = dir;
+       attach->priv = udl_attach;
+
+err_unlock:
+       mutex_unlock(&dev->struct_mutex);
+       return sgt;
+}
+
+static void udl_unmap_dma_buf(struct dma_buf_attachment *attach,
+                             struct sg_table *sgt,
+                             enum dma_data_direction dir)
+{
+       /* Nothing to do. */
+       DRM_DEBUG_PRIME("[DEV:%s] size:%zd dir:%d\n", dev_name(attach->dev),
+                       attach->dmabuf->size, dir);
+}
+
+static void *udl_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num)
+{
+       /* TODO */
+
+       return NULL;
+}
+
+static void *udl_dmabuf_kmap_atomic(struct dma_buf *dma_buf,
+                                   unsigned long page_num)
+{
+       /* TODO */
+
+       return NULL;
+}
+
+static void udl_dmabuf_kunmap(struct dma_buf *dma_buf,
+                             unsigned long page_num, void *addr)
+{
+       /* TODO */
+}
+
+static void udl_dmabuf_kunmap_atomic(struct dma_buf *dma_buf,
+                                    unsigned long page_num,
+                                    void *addr)
+{
+       /* TODO */
+}
+
+static int udl_dmabuf_mmap(struct dma_buf *dma_buf,
+                          struct vm_area_struct *vma)
+{
+       /* TODO */
+
+       return -EINVAL;
+}
+
+static struct dma_buf_ops udl_dmabuf_ops = {
+       .attach                 = udl_attach_dma_buf,
+       .detach                 = udl_detach_dma_buf,
+       .map_dma_buf            = udl_map_dma_buf,
+       .unmap_dma_buf          = udl_unmap_dma_buf,
+       .kmap                   = udl_dmabuf_kmap,
+       .kmap_atomic            = udl_dmabuf_kmap_atomic,
+       .kunmap                 = udl_dmabuf_kunmap,
+       .kunmap_atomic          = udl_dmabuf_kunmap_atomic,
+       .mmap                   = udl_dmabuf_mmap,
+       .release                = drm_gem_dmabuf_release,
+};
+
+struct dma_buf *udl_gem_prime_export(struct drm_device *dev,
+                                    struct drm_gem_object *obj, int flags)
+{
+       return dma_buf_export(obj, &udl_dmabuf_ops, obj->size, flags, NULL);
+}
+
+static int udl_prime_create(struct drm_device *dev,
+                           size_t size,
+                           struct sg_table *sg,
+                           struct udl_gem_object **obj_p)
+{
+       struct udl_gem_object *obj;
+       int npages;
+
+       npages = size / PAGE_SIZE;
+
+       *obj_p = NULL;
+       obj = udl_gem_alloc_object(dev, npages * PAGE_SIZE);
+       if (!obj)
+               return -ENOMEM;
+
+       obj->sg = sg;
+       obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
+       if (obj->pages == NULL) {
+               DRM_ERROR("obj pages is NULL %d\n", npages);
+               return -ENOMEM;
+       }
+
+       drm_prime_sg_to_page_addr_arrays(sg, obj->pages, NULL, npages);
+
+       *obj_p = obj;
+       return 0;
+}
+
+struct drm_gem_object *udl_gem_prime_import(struct drm_device *dev,
+                               struct dma_buf *dma_buf)
+{
+       struct dma_buf_attachment *attach;
+       struct sg_table *sg;
+       struct udl_gem_object *uobj;
+       int ret;
+
+       /* need to attach */
+       get_device(dev->dev);
+       attach = dma_buf_attach(dma_buf, dev->dev);
+       if (IS_ERR(attach)) {
+               put_device(dev->dev);
+               return ERR_CAST(attach);
+       }
+
+       get_dma_buf(dma_buf);
+
+       sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+       if (IS_ERR(sg)) {
+               ret = PTR_ERR(sg);
+               goto fail_detach;
+       }
+
+       ret = udl_prime_create(dev, dma_buf->size, sg, &uobj);
+       if (ret)
+               goto fail_unmap;
+
+       uobj->base.import_attach = attach;
+       uobj->flags = UDL_BO_WC;
+
+       return &uobj->base;
+
+fail_unmap:
+       dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
+fail_detach:
+       dma_buf_detach(dma_buf, attach);
+       dma_buf_put(dma_buf);
+       put_device(dev->dev);
+       return ERR_PTR(ret);
+}
index 8607e9e513db0d94129ea524b9a4abe5dd9653af..d5728ec8525443246aec49b508db2827375242bd 100644 (file)
@@ -51,7 +51,9 @@ static struct drm_driver driver = {
        .dumb_destroy = drm_gem_dumb_destroy,
        .fops = &udl_driver_fops,
 
+       .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
        .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+       .gem_prime_export = udl_gem_prime_export,
        .gem_prime_import = udl_gem_prime_import,
 
        .name = DRIVER_NAME,
index c7490a2489a750c2bc884761300b6b324c5b572a..80adbac82bdedcfb99db9164575ffa6b8787a9f8 100644 (file)
@@ -25,6 +25,9 @@
 #define DRIVER_MINOR           0
 #define DRIVER_PATCHLEVEL      1
 
+#define UDL_BO_CACHEABLE               (1 << 0)
+#define UDL_BO_WC              (1 << 1)
+
 struct udl_device;
 
 struct urb_node {
@@ -69,6 +72,7 @@ struct udl_gem_object {
        struct page **pages;
        void *vmapping;
        struct sg_table *sg;
+       unsigned int flags;
 };
 
 #define to_udl_bo(x) container_of(x, struct udl_gem_object, base)
@@ -120,9 +124,13 @@ int udl_gem_mmap(struct drm_file *file_priv, struct drm_device *dev,
 void udl_gem_free_object(struct drm_gem_object *gem_obj);
 struct udl_gem_object *udl_gem_alloc_object(struct drm_device *dev,
                                            size_t size);
+struct dma_buf *udl_gem_prime_export(struct drm_device *dev,
+                                    struct drm_gem_object *obj, int flags);
 struct drm_gem_object *udl_gem_prime_import(struct drm_device *dev,
                                struct dma_buf *dma_buf);
 
+int udl_gem_get_pages(struct udl_gem_object *obj);
+void udl_gem_put_pages(struct udl_gem_object *obj);
 int udl_gem_vmap(struct udl_gem_object *obj);
 void udl_gem_vunmap(struct udl_gem_object *obj);
 int udl_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
index 8044f5fb7c49a1f5709c6e1d62be72a798d465b8..2a0a784ab6eec37c34143f250fae9851f5d3ea94 100644 (file)
@@ -25,6 +25,7 @@ struct udl_gem_object *udl_gem_alloc_object(struct drm_device *dev,
                return NULL;
        }
 
+       obj->flags = UDL_BO_CACHEABLE;
        return obj;
 }
 
@@ -56,6 +57,23 @@ udl_gem_create(struct drm_file *file,
        return 0;
 }
 
+static void update_vm_cache_attr(struct udl_gem_object *obj,
+                                struct vm_area_struct *vma)
+{
+       DRM_DEBUG_KMS("flags = 0x%x\n", obj->flags);
+
+       /* non-cacheable as default. */
+       if (obj->flags & UDL_BO_CACHEABLE) {
+               vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+       } else if (obj->flags & UDL_BO_WC) {
+               vma->vm_page_prot =
+                       pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+       } else {
+               vma->vm_page_prot =
+                       pgprot_noncached(vm_get_page_prot(vma->vm_flags));
+       }
+}
+
 int udl_dumb_create(struct drm_file *file,
                    struct drm_device *dev,
                    struct drm_mode_create_dumb *args)
@@ -77,6 +95,8 @@ int udl_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
        vma->vm_flags &= ~VM_PFNMAP;
        vma->vm_flags |= VM_MIXEDMAP;
 
+       update_vm_cache_attr(to_udl_bo(vma->vm_private_data), vma);
+
        return ret;
 }
 
@@ -107,7 +127,7 @@ int udl_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        }
 }
 
-static int udl_gem_get_pages(struct udl_gem_object *obj)
+int udl_gem_get_pages(struct udl_gem_object *obj)
 {
        struct page **pages;
 
@@ -123,7 +143,7 @@ static int udl_gem_get_pages(struct udl_gem_object *obj)
        return 0;
 }
 
-static void udl_gem_put_pages(struct udl_gem_object *obj)
+void udl_gem_put_pages(struct udl_gem_object *obj)
 {
        if (obj->base.import_attach) {
                drm_free_large(obj->pages);
@@ -164,8 +184,7 @@ void udl_gem_vunmap(struct udl_gem_object *obj)
                return;
        }
 
-       if (obj->vmapping)
-               vunmap(obj->vmapping);
+       vunmap(obj->vmapping);
 
        udl_gem_put_pages(obj);
 }
@@ -220,73 +239,3 @@ unlock:
        mutex_unlock(&dev->struct_mutex);
        return ret;
 }
-
-static int udl_prime_create(struct drm_device *dev,
-                           size_t size,
-                           struct sg_table *sg,
-                           struct udl_gem_object **obj_p)
-{
-       struct udl_gem_object *obj;
-       int npages;
-
-       npages = size / PAGE_SIZE;
-
-       *obj_p = NULL;
-       obj = udl_gem_alloc_object(dev, npages * PAGE_SIZE);
-       if (!obj)
-               return -ENOMEM;
-
-       obj->sg = sg;
-       obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
-       if (obj->pages == NULL) {
-               DRM_ERROR("obj pages is NULL %d\n", npages);
-               return -ENOMEM;
-       }
-
-       drm_prime_sg_to_page_addr_arrays(sg, obj->pages, NULL, npages);
-
-       *obj_p = obj;
-       return 0;
-}
-
-struct drm_gem_object *udl_gem_prime_import(struct drm_device *dev,
-                               struct dma_buf *dma_buf)
-{
-       struct dma_buf_attachment *attach;
-       struct sg_table *sg;
-       struct udl_gem_object *uobj;
-       int ret;
-
-       /* need to attach */
-       get_device(dev->dev);
-       attach = dma_buf_attach(dma_buf, dev->dev);
-       if (IS_ERR(attach)) {
-               put_device(dev->dev);
-               return ERR_CAST(attach);
-       }
-
-       get_dma_buf(dma_buf);
-
-       sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
-       if (IS_ERR(sg)) {
-               ret = PTR_ERR(sg);
-               goto fail_detach;
-       }
-
-       ret = udl_prime_create(dev, dma_buf->size, sg, &uobj);
-       if (ret) {
-               goto fail_unmap;
-       }
-
-       uobj->base.import_attach = attach;
-
-       return &uobj->base;
-
-fail_unmap:
-       dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
-fail_detach:
-       dma_buf_detach(dma_buf, attach);
-       dma_buf_put(dma_buf);
-       put_device(dev->dev);
-       return ERR_PTR(ret);
-}
index 25f3c250fd98635ff50a7249f40e691686519674..db7621828bc7724205e2481ee4c031f7700f0422 100644 (file)
@@ -889,8 +889,7 @@ static int vmw_driver_unload(struct drm_device *dev)
 
        if (dev_priv->ctx.res_ht_initialized)
                drm_ht_remove(&dev_priv->ctx.res_ht);
-       if (dev_priv->ctx.cmd_bounce)
-               vfree(dev_priv->ctx.cmd_bounce);
+       vfree(dev_priv->ctx.cmd_bounce);
        if (dev_priv->enable_fb) {
                vmw_fb_close(dev_priv);
                vmw_kms_restore_vga(dev_priv);
index 941a7bc0b79190b7bcafe751cd7cac26b371911e..3725b521d9319c9b952bf3920bfcd3a27c61dac3 100644 (file)
@@ -252,7 +252,7 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
        ret = 0;
 out:
        drm_modeset_unlock_all(dev_priv->dev);
-       drm_modeset_lock_crtc(crtc);
+       drm_modeset_lock_crtc(crtc, crtc->cursor);
 
        return ret;
 }
@@ -281,7 +281,7 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
                                   du->cursor_y + du->hotspot_y);
 
        drm_modeset_unlock_all(dev_priv->dev);
-       drm_modeset_lock_crtc(crtc);
+       drm_modeset_lock_crtc(crtc, crtc->cursor);
 
        return 0;
 }
index 3995255b16c753731420cb8283992c17c33ddf2e..5a8c8d55317ab4f622c5754f509d5d3660a3e47c 100644 (file)
@@ -97,7 +97,7 @@ fail:
 static void host1x_pushbuffer_push(struct push_buffer *pb, u32 op1, u32 op2)
 {
        u32 pos = pb->pos;
-       u32 *p = (u32 *)((u32)pb->mapped + pos);
+       u32 *p = (u32 *)((void *)pb->mapped + pos);
        WARN_ON(pos == pb->fence);
        *(p++) = op1;
        *(p++) = op2;
index 313c4b7843483ab4d0b6d31c1d76d754e2320b38..470087af8fe520681ba3cc8457646343f16f6aee 100644 (file)
@@ -42,7 +42,7 @@ struct host1x_job;
  */
 
 struct push_buffer {
-       u32 *mapped;                    /* mapped pushbuffer memory */
+       void *mapped;                   /* mapped pushbuffer memory */
        dma_addr_t phys;                /* physical address of pushbuffer */
        u32 fence;                      /* index we've written */
        u32 pos;                        /* index to write to */
index 6b09b71940c2d5df0251ec2b3cd417ec2eb93e2d..305ea8f3382d22da2611e6de7025695265d97699 100644 (file)
 #include "../debug.h"
 
 /*
- * Put the restart at the end of pushbuffer memor
+ * Put the restart at the end of pushbuffer memory
  */
 static void push_buffer_init(struct push_buffer *pb)
 {
-       *(pb->mapped + (pb->size_bytes >> 2)) = host1x_opcode_restart(0);
+       *(u32 *)(pb->mapped + pb->size_bytes) = host1x_opcode_restart(0);
 }
 
 /*
@@ -51,11 +51,11 @@ static void cdma_timeout_cpu_incr(struct host1x_cdma *cdma, u32 getptr,
 
        /* NOP all the PB slots */
        while (nr_slots--) {
-               u32 *p = (u32 *)((u32)pb->mapped + getptr);
+               u32 *p = (u32 *)(pb->mapped + getptr);
                *(p++) = HOST1X_OPCODE_NOP;
                *(p++) = HOST1X_OPCODE_NOP;
-               dev_dbg(host1x->dev, "%s: NOP at %#llx\n", __func__,
-                       (u64)pb->phys + getptr);
+               dev_dbg(host1x->dev, "%s: NOP at %pad+%#x\n", __func__,
+                       &pb->phys, getptr);
                getptr = (getptr + 8) & (pb->size_bytes - 1);
        }
        wmb();
index 4608257ab65641c488f627a0789eae9a4ba90ff1..946c332c3906ad823826b56b0c25a3300715424c 100644 (file)
@@ -32,6 +32,7 @@
 static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo,
                               u32 offset, u32 words)
 {
+       struct device *dev = cdma_to_channel(cdma)->dev;
        void *mem = NULL;
 
        if (host1x_debug_trace_cmdbuf)
@@ -44,11 +45,14 @@ static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo,
                 * of how much you can output to ftrace at once.
                 */
                for (i = 0; i < words; i += TRACE_MAX_LENGTH) {
-                       trace_host1x_cdma_push_gather(
-                               dev_name(cdma_to_channel(cdma)->dev),
-                               (u32)bo, min(words - i, TRACE_MAX_LENGTH),
-                               offset + i * sizeof(u32), mem);
+                       u32 num_words = min(words - i, TRACE_MAX_LENGTH);
+                       offset += i * sizeof(u32);
+
+                       trace_host1x_cdma_push_gather(dev_name(dev), bo,
+                                                     num_words, offset,
+                                                     mem);
                }
+
                host1x_bo_munmap(bo, mem);
        }
 }
index f72c873eff819f831202a742cf02ec70e94753f2..791de9351eebff26946919c6b7b3e747489d2579 100644 (file)
@@ -163,8 +163,8 @@ static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma)
                                continue;
                        }
 
-                       host1x_debug_output(o, "    GATHER at %#llx+%04x, %d words\n",
-                                           (u64)g->base, g->offset, g->words);
+                       host1x_debug_output(o, "    GATHER at %pad+%#x, %d words\n",
+                                           &g->base, g->offset, g->words);
 
                        show_gather(o, g->base + g->offset, g->words, cdma,
                                    g->base, mapped);
index 33a697d6dcefea290c3bac2981e2399e27f99a14..8b3c15df066085e88a33d6efddc74cfd774bc04d 100644 (file)
@@ -23,7 +23,7 @@ struct host1x_job_gather {
        u32 words;
        dma_addr_t base;
        struct host1x_bo *bo;
-       int offset;
+       u32 offset;
        bool handled;
 };
 
index 9882ea122024e8f56c47e7b7b13f75b3a7f330aa..fbc6ee6ca3374276219c5a8ae5beab08f8149005 100644 (file)
 #define MIPI_CAL_CONFIG_DSIC           0x10
 #define MIPI_CAL_CONFIG_DSID           0x11
 
+#define MIPI_CAL_CONFIG_DSIAB_CLK      0x19
+#define MIPI_CAL_CONFIG_DSICD_CLK      0x1a
+#define MIPI_CAL_CONFIG_CSIAB_CLK      0x1b
+#define MIPI_CAL_CONFIG_CSICD_CLK      0x1c
+#define MIPI_CAL_CONFIG_CSIE_CLK       0x1d
+
+/* for data and clock lanes */
 #define MIPI_CAL_CONFIG_SELECT         (1 << 21)
+
+/* for data lanes */
 #define MIPI_CAL_CONFIG_HSPDOS(x)      (((x) & 0x1f) << 16)
 #define MIPI_CAL_CONFIG_HSPUOS(x)      (((x) & 0x1f) <<  8)
 #define MIPI_CAL_CONFIG_TERMOS(x)      (((x) & 0x1f) <<  0)
 
+/* for clock lanes */
+#define MIPI_CAL_CONFIG_HSCLKPDOSD(x)  (((x) & 0x1f) <<  8)
+#define MIPI_CAL_CONFIG_HSCLKPUOSD(x)  (((x) & 0x1f) <<  0)
+
 #define MIPI_CAL_BIAS_PAD_CFG0         0x16
 #define MIPI_CAL_BIAS_PAD_PDVCLAMP     (1 << 1)
 #define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF (1 << 0)
 
 #define MIPI_CAL_BIAS_PAD_CFG1         0x17
+#define MIPI_CAL_BIAS_PAD_DRV_DN_REF(x) (((x) & 0x7) << 16)
 
 #define MIPI_CAL_BIAS_PAD_CFG2         0x18
 #define MIPI_CAL_BIAS_PAD_PDVREG       (1 << 1)
 
-static const struct module {
-       unsigned long reg;
-} modules[] = {
-       { .reg = MIPI_CAL_CONFIG_CSIA },
-       { .reg = MIPI_CAL_CONFIG_CSIB },
-       { .reg = MIPI_CAL_CONFIG_CSIC },
-       { .reg = MIPI_CAL_CONFIG_CSID },
-       { .reg = MIPI_CAL_CONFIG_CSIE },
-       { .reg = MIPI_CAL_CONFIG_DSIA },
-       { .reg = MIPI_CAL_CONFIG_DSIB },
-       { .reg = MIPI_CAL_CONFIG_DSIC },
-       { .reg = MIPI_CAL_CONFIG_DSID },
+struct tegra_mipi_pad {
+       unsigned long data;
+       unsigned long clk;
+};
+
+struct tegra_mipi_soc {
+       bool has_clk_lane;
+       const struct tegra_mipi_pad *pads;
+       unsigned int num_pads;
 };
 
 struct tegra_mipi {
+       const struct tegra_mipi_soc *soc;
        void __iomem *regs;
        struct mutex lock;
        struct clk *clk;
@@ -90,16 +102,16 @@ struct tegra_mipi_device {
        unsigned long pads;
 };
 
-static inline unsigned long tegra_mipi_readl(struct tegra_mipi *mipi,
-                                            unsigned long reg)
+static inline u32 tegra_mipi_readl(struct tegra_mipi *mipi,
+                                  unsigned long offset)
 {
-       return readl(mipi->regs + (reg << 2));
+       return readl(mipi->regs + (offset << 2));
 }
 
-static inline void tegra_mipi_writel(struct tegra_mipi *mipi,
-                                    unsigned long value, unsigned long reg)
+static inline void tegra_mipi_writel(struct tegra_mipi *mipi, u32 value,
+                                    unsigned long offset)
 {
-       writel(value, mipi->regs + (reg << 2));
+       writel(value, mipi->regs + (offset << 2));
 }
 
 struct tegra_mipi_device *tegra_mipi_request(struct device *device)
@@ -117,36 +129,35 @@ struct tegra_mipi_device *tegra_mipi_request(struct device *device)
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev) {
-               of_node_put(args.np);
                err = -ENOMEM;
                goto out;
        }
 
        dev->pdev = of_find_device_by_node(args.np);
        if (!dev->pdev) {
-               of_node_put(args.np);
                err = -ENODEV;
                goto free;
        }
 
-       of_node_put(args.np);
-
        dev->mipi = platform_get_drvdata(dev->pdev);
        if (!dev->mipi) {
                err = -EPROBE_DEFER;
-               goto pdev_put;
+               goto put;
        }
 
+       of_node_put(args.np);
+
        dev->pads = args.args[0];
        dev->device = device;
 
        return dev;
 
-pdev_put:
+put:
        platform_device_put(dev->pdev);
 free:
        kfree(dev);
 out:
+       of_node_put(args.np);
        return ERR_PTR(err);
 }
 EXPORT_SYMBOL(tegra_mipi_request);
@@ -161,7 +172,7 @@ EXPORT_SYMBOL(tegra_mipi_free);
 static int tegra_mipi_wait(struct tegra_mipi *mipi)
 {
        unsigned long timeout = jiffies + msecs_to_jiffies(250);
-       unsigned long value;
+       u32 value;
 
        while (time_before(jiffies, timeout)) {
                value = tegra_mipi_readl(mipi, MIPI_CAL_STATUS);
@@ -177,8 +188,9 @@ static int tegra_mipi_wait(struct tegra_mipi *mipi)
 
 int tegra_mipi_calibrate(struct tegra_mipi_device *device)
 {
-       unsigned long value;
+       const struct tegra_mipi_soc *soc = device->mipi->soc;
        unsigned int i;
+       u32 value;
        int err;
 
        err = clk_enable(device->mipi->clk);
@@ -192,23 +204,35 @@ int tegra_mipi_calibrate(struct tegra_mipi_device *device)
        value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF;
        tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG0);
 
+       tegra_mipi_writel(device->mipi, MIPI_CAL_BIAS_PAD_DRV_DN_REF(2),
+                         MIPI_CAL_BIAS_PAD_CFG1);
+
        value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2);
        value &= ~MIPI_CAL_BIAS_PAD_PDVREG;
        tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2);
 
-       for (i = 0; i < ARRAY_SIZE(modules); i++) {
-               if (device->pads & BIT(i))
-                       value = MIPI_CAL_CONFIG_SELECT |
-                               MIPI_CAL_CONFIG_HSPDOS(0) |
-                               MIPI_CAL_CONFIG_HSPUOS(4) |
-                               MIPI_CAL_CONFIG_TERMOS(5);
-               else
-                       value = 0;
+       for (i = 0; i < soc->num_pads; i++) {
+               u32 clk = 0, data = 0;
+
+               if (device->pads & BIT(i)) {
+                       data = MIPI_CAL_CONFIG_SELECT |
+                              MIPI_CAL_CONFIG_HSPDOS(0) |
+                              MIPI_CAL_CONFIG_HSPUOS(4) |
+                              MIPI_CAL_CONFIG_TERMOS(5);
+                       clk = MIPI_CAL_CONFIG_SELECT |
+                             MIPI_CAL_CONFIG_HSCLKPDOSD(0) |
+                             MIPI_CAL_CONFIG_HSCLKPUOSD(4);
+               }
 
-               tegra_mipi_writel(device->mipi, value, modules[i].reg);
+               tegra_mipi_writel(device->mipi, data, soc->pads[i].data);
+
+               if (soc->has_clk_lane)
+                       tegra_mipi_writel(device->mipi, clk, soc->pads[i].clk);
        }
 
-       tegra_mipi_writel(device->mipi, MIPI_CAL_CTRL_START, MIPI_CAL_CTRL);
+       value = tegra_mipi_readl(device->mipi, MIPI_CAL_CTRL);
+       value |= MIPI_CAL_CTRL_START;
+       tegra_mipi_writel(device->mipi, value, MIPI_CAL_CTRL);
 
        err = tegra_mipi_wait(device->mipi);
 
@@ -219,16 +243,63 @@ int tegra_mipi_calibrate(struct tegra_mipi_device *device)
 }
 EXPORT_SYMBOL(tegra_mipi_calibrate);
 
+static const struct tegra_mipi_pad tegra114_mipi_pads[] = {
+       { .data = MIPI_CAL_CONFIG_CSIA },
+       { .data = MIPI_CAL_CONFIG_CSIB },
+       { .data = MIPI_CAL_CONFIG_CSIC },
+       { .data = MIPI_CAL_CONFIG_CSID },
+       { .data = MIPI_CAL_CONFIG_CSIE },
+       { .data = MIPI_CAL_CONFIG_DSIA },
+       { .data = MIPI_CAL_CONFIG_DSIB },
+       { .data = MIPI_CAL_CONFIG_DSIC },
+       { .data = MIPI_CAL_CONFIG_DSID },
+};
+
+static const struct tegra_mipi_soc tegra114_mipi_soc = {
+       .has_clk_lane = false,
+       .pads = tegra114_mipi_pads,
+       .num_pads = ARRAY_SIZE(tegra114_mipi_pads),
+};
+
+static const struct tegra_mipi_pad tegra124_mipi_pads[] = {
+       { .data = MIPI_CAL_CONFIG_CSIA, .clk = MIPI_CAL_CONFIG_CSIAB_CLK },
+       { .data = MIPI_CAL_CONFIG_CSIB, .clk = MIPI_CAL_CONFIG_CSIAB_CLK },
+       { .data = MIPI_CAL_CONFIG_CSIC, .clk = MIPI_CAL_CONFIG_CSICD_CLK },
+       { .data = MIPI_CAL_CONFIG_CSID, .clk = MIPI_CAL_CONFIG_CSICD_CLK },
+       { .data = MIPI_CAL_CONFIG_CSIE, .clk = MIPI_CAL_CONFIG_CSIE_CLK },
+       { .data = MIPI_CAL_CONFIG_DSIA, .clk = MIPI_CAL_CONFIG_DSIAB_CLK },
+       { .data = MIPI_CAL_CONFIG_DSIB, .clk = MIPI_CAL_CONFIG_DSIAB_CLK },
+};
+
+static const struct tegra_mipi_soc tegra124_mipi_soc = {
+       .has_clk_lane = true,
+       .pads = tegra124_mipi_pads,
+       .num_pads = ARRAY_SIZE(tegra124_mipi_pads),
+};
+
+static struct of_device_id tegra_mipi_of_match[] = {
+       { .compatible = "nvidia,tegra114-mipi", .data = &tegra114_mipi_soc },
+       { .compatible = "nvidia,tegra124-mipi", .data = &tegra124_mipi_soc },
+       { },
+};
+
 static int tegra_mipi_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *match;
        struct tegra_mipi *mipi;
        struct resource *res;
        int err;
 
+       match = of_match_node(tegra_mipi_of_match, pdev->dev.of_node);
+       if (!match)
+               return -ENODEV;
+
        mipi = devm_kzalloc(&pdev->dev, sizeof(*mipi), GFP_KERNEL);
        if (!mipi)
                return -ENOMEM;
 
+       mipi->soc = match->data;
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        mipi->regs = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(mipi->regs))
@@ -260,11 +331,6 @@ static int tegra_mipi_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct of_device_id tegra_mipi_of_match[] = {
-       { .compatible = "nvidia,tegra114-mipi", },
-       { },
-};
-
 struct platform_driver tegra_mipi_driver = {
        .driver = {
                .name = "tegra-mipi",
index 6aac695b1688beaf2adc5336bd842bb7993d2d09..9b55e673b67caf1365c7452ce51a22a37510af02 100644 (file)
@@ -1084,10 +1084,8 @@ static int g762_probe(struct i2c_client *client, const struct i2c_device_id *id)
        if (ret)
                goto clock_dis;
 
-       data->hwmon_dev = devm_hwmon_device_register_with_groups(dev,
-                                                                client->name,
-                                                                data,
-                                                                g762_groups);
+       data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name,
+                                                           data, g762_groups);
        if (IS_ERR(data->hwmon_dev)) {
                ret = PTR_ERR(data->hwmon_dev);
                goto clock_dis;
index 22c096ce39ad765c6a50d26ff80e77158fe3bbf6..513bd6d14293d80e5ce502080a092b5f970fe840 100644 (file)
@@ -44,6 +44,9 @@
 
 #define BMC150_ACCEL_REG_INT_STATUS_2          0x0B
 #define BMC150_ACCEL_ANY_MOTION_MASK           0x07
+#define BMC150_ACCEL_ANY_MOTION_BIT_X          BIT(0)
+#define BMC150_ACCEL_ANY_MOTION_BIT_Y          BIT(1)
+#define BMC150_ACCEL_ANY_MOTION_BIT_Z          BIT(2)
 #define BMC150_ACCEL_ANY_MOTION_BIT_SIGN       BIT(3)
 
 #define BMC150_ACCEL_REG_PMU_LPW               0x11
@@ -92,9 +95,9 @@
 #define BMC150_ACCEL_SLOPE_THRES_MASK          0xFF
 
 /* Slope duration in terms of number of samples */
-#define BMC150_ACCEL_DEF_SLOPE_DURATION        2
+#define BMC150_ACCEL_DEF_SLOPE_DURATION                1
 /* in terms of multiples of g's/LSB, based on range */
-#define BMC150_ACCEL_DEF_SLOPE_THRESHOLD       5
+#define BMC150_ACCEL_DEF_SLOPE_THRESHOLD       1
 
 #define BMC150_ACCEL_REG_XOUT_L                0x02
 
@@ -536,6 +539,9 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
        if (ret < 0) {
                dev_err(&data->client->dev,
                        "Failed: bmc150_accel_set_power_state for %d\n", on);
+               if (on)
+                       pm_runtime_put_noidle(&data->client->dev);
+
                return ret;
        }
 
@@ -811,6 +817,7 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev,
 
        ret =  bmc150_accel_setup_any_motion_interrupt(data, state);
        if (ret < 0) {
+               bmc150_accel_set_power_state(data, false);
                mutex_unlock(&data->mutex);
                return ret;
        }
@@ -846,7 +853,7 @@ static const struct attribute_group bmc150_accel_attrs_group = {
 
 static const struct iio_event_spec bmc150_accel_event = {
                .type = IIO_EV_TYPE_ROC,
-               .dir = IIO_EV_DIR_RISING | IIO_EV_DIR_FALLING,
+               .dir = IIO_EV_DIR_EITHER,
                .mask_separate = BIT(IIO_EV_INFO_VALUE) |
                                 BIT(IIO_EV_INFO_ENABLE) |
                                 BIT(IIO_EV_INFO_PERIOD)
@@ -1054,6 +1061,7 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig,
        else
                ret = bmc150_accel_setup_new_data_interrupt(data, state);
        if (ret < 0) {
+               bmc150_accel_set_power_state(data, false);
                mutex_unlock(&data->mutex);
                return ret;
        }
@@ -1092,12 +1100,26 @@ static irqreturn_t bmc150_accel_event_handler(int irq, void *private)
        else
                dir = IIO_EV_DIR_RISING;
 
-       if (ret & BMC150_ACCEL_ANY_MOTION_MASK)
+       if (ret & BMC150_ACCEL_ANY_MOTION_BIT_X)
+               iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL,
+                                                       0,
+                                                       IIO_MOD_X,
+                                                       IIO_EV_TYPE_ROC,
+                                                       dir),
+                                                       data->timestamp);
+       if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Y)
                iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL,
                                                        0,
-                                                       IIO_MOD_X_OR_Y_OR_Z,
+                                                       IIO_MOD_Y,
                                                        IIO_EV_TYPE_ROC,
-                                                       IIO_EV_DIR_EITHER),
+                                                       dir),
+                                                       data->timestamp);
+       if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Z)
+               iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL,
+                                                       0,
+                                                       IIO_MOD_Z,
+                                                       IIO_EV_TYPE_ROC,
+                                                       dir),
                                                        data->timestamp);
 ack_intr_status:
        if (!data->dready_trigger_on)
@@ -1354,10 +1376,14 @@ static int bmc150_accel_runtime_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
        struct bmc150_accel_data *data = iio_priv(indio_dev);
+       int ret;
 
        dev_dbg(&data->client->dev,  __func__);
+       ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0);
+       if (ret < 0)
+               return -EAGAIN;
 
-       return bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0);
+       return 0;
 }
 
 static int bmc150_accel_runtime_resume(struct device *dev)
index a23e58c4ed99b222b674ce2386c9c36a3809efbe..320aa72c0349ecabeae7ea4a0bdb59d2c84cd63d 100644 (file)
@@ -269,6 +269,8 @@ static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index)
                return ret;
        }
 
+       ret &= ~(KXCJK1013_REG_CTRL1_BIT_GSEL0 |
+                KXCJK1013_REG_CTRL1_BIT_GSEL1);
        ret |= (KXCJK1013_scale_table[range_index].gsel_0 << 3);
        ret |= (KXCJK1013_scale_table[range_index].gsel_1 << 4);
 
index b58d6302521f4d651359715331e83a5a416583a0..d095efe1ba149caa57136ec1f27f1c6caac10cd8 100644 (file)
@@ -152,6 +152,7 @@ static void men_z188_remove(struct mcb_device *dev)
 
 static const struct mcb_device_id men_z188_ids[] = {
        { .device = 0xbc },
+       { }
 };
 MODULE_DEVICE_TABLE(mcb, men_z188_ids);
 
index 1f967e0d688e47a084f29e2b484621016ada7c3c..d2fa526740ca188e00926f42b733af91d4dcd9df 100644 (file)
@@ -67,6 +67,9 @@
 #define BMG160_REG_INT_EN_0            0x15
 #define BMG160_DATA_ENABLE_INT         BIT(7)
 
+#define BMG160_REG_INT_EN_1            0x16
+#define BMG160_INT1_BIT_OD             BIT(1)
+
 #define BMG160_REG_XOUT_L              0x02
 #define BMG160_AXIS_TO_REG(axis)       (BMG160_REG_XOUT_L + (axis * 2))
 
@@ -82,6 +85,9 @@
 
 #define BMG160_REG_INT_STATUS_2        0x0B
 #define BMG160_ANY_MOTION_MASK         0x07
+#define BMG160_ANY_MOTION_BIT_X                BIT(0)
+#define BMG160_ANY_MOTION_BIT_Y                BIT(1)
+#define BMG160_ANY_MOTION_BIT_Z                BIT(2)
 
 #define BMG160_REG_TEMP                0x08
 #define BMG160_TEMP_CENTER_VAL         23
@@ -222,6 +228,19 @@ static int bmg160_chip_init(struct bmg160_data *data)
        data->slope_thres = ret;
 
        /* Set default interrupt mode */
+       ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_INT_EN_1);
+       if (ret < 0) {
+               dev_err(&data->client->dev, "Error reading reg_int_en_1\n");
+               return ret;
+       }
+       ret &= ~BMG160_INT1_BIT_OD;
+       ret = i2c_smbus_write_byte_data(data->client,
+                                       BMG160_REG_INT_EN_1, ret);
+       if (ret < 0) {
+               dev_err(&data->client->dev, "Error writing reg_int_en_1\n");
+               return ret;
+       }
+
        ret = i2c_smbus_write_byte_data(data->client,
                                        BMG160_REG_INT_RST_LATCH,
                                        BMG160_INT_MODE_LATCH_INT |
@@ -250,6 +269,9 @@ static int bmg160_set_power_state(struct bmg160_data *data, bool on)
        if (ret < 0) {
                dev_err(&data->client->dev,
                        "Failed: bmg160_set_power_state for %d\n", on);
+               if (on)
+                       pm_runtime_put_noidle(&data->client->dev);
+
                return ret;
        }
 #endif
@@ -705,6 +727,7 @@ static int bmg160_write_event_config(struct iio_dev *indio_dev,
 
        ret =  bmg160_setup_any_motion_interrupt(data, state);
        if (ret < 0) {
+               bmg160_set_power_state(data, false);
                mutex_unlock(&data->mutex);
                return ret;
        }
@@ -743,7 +766,7 @@ static const struct attribute_group bmg160_attrs_group = {
 
 static const struct iio_event_spec bmg160_event = {
                .type = IIO_EV_TYPE_ROC,
-               .dir = IIO_EV_DIR_RISING | IIO_EV_DIR_FALLING,
+               .dir = IIO_EV_DIR_EITHER,
                .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
                                       BIT(IIO_EV_INFO_ENABLE)
 };
@@ -871,6 +894,7 @@ static int bmg160_data_rdy_trigger_set_state(struct iio_trigger *trig,
        else
                ret = bmg160_setup_new_data_interrupt(data, state);
        if (ret < 0) {
+               bmg160_set_power_state(data, false);
                mutex_unlock(&data->mutex);
                return ret;
        }
@@ -908,10 +932,24 @@ static irqreturn_t bmg160_event_handler(int irq, void *private)
        else
                dir = IIO_EV_DIR_FALLING;
 
-       if (ret & BMG160_ANY_MOTION_MASK)
+       if (ret & BMG160_ANY_MOTION_BIT_X)
                iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
                                                        0,
-                                                       IIO_MOD_X_OR_Y_OR_Z,
+                                                       IIO_MOD_X,
+                                                       IIO_EV_TYPE_ROC,
+                                                       dir),
+                                                       data->timestamp);
+       if (ret & BMG160_ANY_MOTION_BIT_Y)
+               iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
+                                                       0,
+                                                       IIO_MOD_Y,
+                                                       IIO_EV_TYPE_ROC,
+                                                       dir),
+                                                       data->timestamp);
+       if (ret & BMG160_ANY_MOTION_BIT_Z)
+               iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
+                                                       0,
+                                                       IIO_MOD_Z,
                                                        IIO_EV_TYPE_ROC,
                                                        dir),
                                                        data->timestamp);
@@ -1169,8 +1207,15 @@ static int bmg160_runtime_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
        struct bmg160_data *data = iio_priv(indio_dev);
+       int ret;
+
+       ret = bmg160_set_mode(data, BMG160_MODE_SUSPEND);
+       if (ret < 0) {
+               dev_err(&data->client->dev, "set mode failed\n");
+               return -EAGAIN;
+       }
 
-       return bmg160_set_mode(data, BMG160_MODE_SUSPEND);
+       return 0;
 }
 
 static int bmg160_runtime_resume(struct device *dev)
index 3effa931fce259cdf661af95f42ad1463450acf4..10641b7816f49e493dd2e1f091d0921d910c2475 100644 (file)
@@ -115,9 +115,12 @@ isert_conn_setup_qp(struct isert_conn *isert_conn, struct rdma_cm_id *cma_id,
        attr.cap.max_recv_wr = ISERT_QP_MAX_RECV_DTOS;
        /*
         * FIXME: Use devattr.max_sge - 2 for max_send_sge as
-        * work-around for RDMA_READ..
+        * work-around for RDMA_READs with ConnectX-2.
+        *
+        * Also, still make sure to have at least two SGEs for
+        * outgoing control PDU responses.
         */
-       attr.cap.max_send_sge = device->dev_attr.max_sge - 2;
+       attr.cap.max_send_sge = max(2, device->dev_attr.max_sge - 2);
        isert_conn->max_sge = attr.cap.max_send_sge;
 
        attr.cap.max_recv_sge = 1;
@@ -225,12 +228,16 @@ isert_create_device_ib_res(struct isert_device *device)
        struct isert_cq_desc *cq_desc;
        struct ib_device_attr *dev_attr;
        int ret = 0, i, j;
+       int max_rx_cqe, max_tx_cqe;
 
        dev_attr = &device->dev_attr;
        ret = isert_query_device(ib_dev, dev_attr);
        if (ret)
                return ret;
 
+       max_rx_cqe = min(ISER_MAX_RX_CQ_LEN, dev_attr->max_cqe);
+       max_tx_cqe = min(ISER_MAX_TX_CQ_LEN, dev_attr->max_cqe);
+
        /* asign function handlers */
        if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS &&
            dev_attr->device_cap_flags & IB_DEVICE_SIGNATURE_HANDOVER) {
@@ -272,7 +279,7 @@ isert_create_device_ib_res(struct isert_device *device)
                                                isert_cq_rx_callback,
                                                isert_cq_event_callback,
                                                (void *)&cq_desc[i],
-                                               ISER_MAX_RX_CQ_LEN, i);
+                                               max_rx_cqe, i);
                if (IS_ERR(device->dev_rx_cq[i])) {
                        ret = PTR_ERR(device->dev_rx_cq[i]);
                        device->dev_rx_cq[i] = NULL;
@@ -284,7 +291,7 @@ isert_create_device_ib_res(struct isert_device *device)
                                                isert_cq_tx_callback,
                                                isert_cq_event_callback,
                                                (void *)&cq_desc[i],
-                                               ISER_MAX_TX_CQ_LEN, i);
+                                               max_tx_cqe, i);
                if (IS_ERR(device->dev_tx_cq[i])) {
                        ret = PTR_ERR(device->dev_tx_cq[i]);
                        device->dev_tx_cq[i] = NULL;
@@ -803,14 +810,25 @@ wake_up:
        complete(&isert_conn->conn_wait);
 }
 
-static void
+static int
 isert_disconnected_handler(struct rdma_cm_id *cma_id, bool disconnect)
 {
-       struct isert_conn *isert_conn = (struct isert_conn *)cma_id->context;
+       struct isert_conn *isert_conn;
+
+       if (!cma_id->qp) {
+               struct isert_np *isert_np = cma_id->context;
+
+               isert_np->np_cm_id = NULL;
+               return -1;
+       }
+
+       isert_conn = (struct isert_conn *)cma_id->context;
 
        isert_conn->disconnect = disconnect;
        INIT_WORK(&isert_conn->conn_logout_work, isert_disconnect_work);
        schedule_work(&isert_conn->conn_logout_work);
+
+       return 0;
 }
 
 static int
@@ -825,6 +843,9 @@ isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
        switch (event->event) {
        case RDMA_CM_EVENT_CONNECT_REQUEST:
                ret = isert_connect_request(cma_id, event);
+               if (ret)
+                       pr_err("isert_cma_handler failed RDMA_CM_EVENT: 0x%08x %d\n",
+                               event->event, ret);
                break;
        case RDMA_CM_EVENT_ESTABLISHED:
                isert_connected_handler(cma_id);
@@ -834,7 +855,7 @@ isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
        case RDMA_CM_EVENT_DEVICE_REMOVAL: /* FALLTHRU */
                disconnect = true;
        case RDMA_CM_EVENT_TIMEWAIT_EXIT:  /* FALLTHRU */
-               isert_disconnected_handler(cma_id, disconnect);
+               ret = isert_disconnected_handler(cma_id, disconnect);
                break;
        case RDMA_CM_EVENT_CONNECT_ERROR:
        default:
@@ -842,12 +863,6 @@ isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
                break;
        }
 
-       if (ret != 0) {
-               pr_err("isert_cma_handler failed RDMA_CM_EVENT: 0x%08x %d\n",
-                      event->event, ret);
-               dump_stack();
-       }
-
        return ret;
 }
 
@@ -3190,7 +3205,8 @@ isert_free_np(struct iscsi_np *np)
 {
        struct isert_np *isert_np = (struct isert_np *)np->np_context;
 
-       rdma_destroy_id(isert_np->np_cm_id);
+       if (isert_np->np_cm_id)
+               rdma_destroy_id(isert_np->np_cm_id);
 
        np->np_context = NULL;
        kfree(isert_np);
index 7206547c13ce0dc8dda59458658d843d64520327..dc829682701ad1dbae8375eb2ff9a2c97feea48f 100644 (file)
@@ -2092,6 +2092,7 @@ static int srpt_create_ch_ib(struct srpt_rdma_ch *ch)
        if (!qp_init)
                goto out;
 
+retry:
        ch->cq = ib_create_cq(sdev->device, srpt_completion, NULL, ch,
                              ch->rq_size + srp_sq_size, 0);
        if (IS_ERR(ch->cq)) {
@@ -2115,6 +2116,13 @@ static int srpt_create_ch_ib(struct srpt_rdma_ch *ch)
        ch->qp = ib_create_qp(sdev->pd, qp_init);
        if (IS_ERR(ch->qp)) {
                ret = PTR_ERR(ch->qp);
+               if (ret == -ENOMEM) {
+                       srp_sq_size /= 2;
+                       if (srp_sq_size >= MIN_SRPT_SQ_SIZE) {
+                               ib_destroy_cq(ch->cq);
+                               goto retry;
+                       }
+               }
                printk(KERN_ERR "failed to create_qp ret= %d\n", ret);
                goto err_destroy_cq;
        }
index 2ed7905a068fc9033e8998e547bd7d750b1fedb9..fc55f0d15b70118a3a5be5fc221f151475f014e3 100644 (file)
@@ -1179,9 +1179,19 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                }
 
                ep_irq_in = &intf->cur_altsetting->endpoint[1].desc;
-               usb_fill_bulk_urb(xpad->bulk_out, udev,
-                               usb_sndbulkpipe(udev, ep_irq_in->bEndpointAddress),
-                               xpad->bdata, XPAD_PKT_LEN, xpad_bulk_out, xpad);
+               if (usb_endpoint_is_bulk_out(ep_irq_in)) {
+                       usb_fill_bulk_urb(xpad->bulk_out, udev,
+                                         usb_sndbulkpipe(udev,
+                                                         ep_irq_in->bEndpointAddress),
+                                         xpad->bdata, XPAD_PKT_LEN,
+                                         xpad_bulk_out, xpad);
+               } else {
+                       usb_fill_int_urb(xpad->bulk_out, udev,
+                                        usb_sndintpipe(udev,
+                                                       ep_irq_in->bEndpointAddress),
+                                        xpad->bdata, XPAD_PKT_LEN,
+                                        xpad_bulk_out, xpad, 0);
+               }
 
                /*
                 * Submit the int URB immediately rather than waiting for open
index 3fcb6b3cb0bdaea5ba0f17dfd6a228c6cbd126ad..f2b97802640755aacfcde04005b125717cb63818 100644 (file)
@@ -428,14 +428,6 @@ static void elantech_report_trackpoint(struct psmouse *psmouse,
        int x, y;
        u32 t;
 
-       if (dev_WARN_ONCE(&psmouse->ps2dev.serio->dev,
-                         !tp_dev,
-                         psmouse_fmt("Unexpected trackpoint message\n"))) {
-               if (etd->debug == 1)
-                       elantech_packet_dump(psmouse);
-               return;
-       }
-
        t = get_unaligned_le32(&packet[0]);
 
        switch (t & ~7U) {
@@ -793,7 +785,7 @@ static int elantech_packet_check_v4(struct psmouse *psmouse)
        unsigned char packet_type = packet[3] & 0x03;
        bool sanity_check;
 
-       if ((packet[3] & 0x0f) == 0x06)
+       if (etd->tp_dev && (packet[3] & 0x0f) == 0x06)
                return PACKET_TRACKPOINT;
 
        /*
index 2a7a9174c702a44df3072a2f61c72a4ce16ecb05..f9472920d986368f7aa83eb7d0621489d774b050 100644 (file)
@@ -143,6 +143,10 @@ static const struct min_max_quirk min_max_pnpid_table[] = {
                (const char * const []){"LEN2001", NULL},
                1024, 5022, 2508, 4832
        },
+       {
+               (const char * const []){"LEN2006", NULL},
+               1264, 5675, 1171, 4688
+       },
        { }
 };
 
index 90d734bbf467a2cec462282191f64c8f2131c1ae..1e6360e7ae44790bb28cb6c11be043637c4d0652 100644 (file)
@@ -92,13 +92,6 @@ static spinlock_t state_lock;
 
 static struct workqueue_struct *iommu_wq;
 
-/*
- * Empty page table - Used between
- * mmu_notifier_invalidate_range_start and
- * mmu_notifier_invalidate_range_end
- */
-static u64 *empty_page_table;
-
 static void free_pasid_states(struct device_state *dev_state);
 
 static u16 device_id(struct pci_dev *pdev)
@@ -279,10 +272,8 @@ static void free_pasid_state(struct pasid_state *pasid_state)
 
 static void put_pasid_state(struct pasid_state *pasid_state)
 {
-       if (atomic_dec_and_test(&pasid_state->count)) {
-               put_device_state(pasid_state->device_state);
+       if (atomic_dec_and_test(&pasid_state->count))
                wake_up(&pasid_state->wq);
-       }
 }
 
 static void put_pasid_state_wait(struct pasid_state *pasid_state)
@@ -291,9 +282,7 @@ static void put_pasid_state_wait(struct pasid_state *pasid_state)
 
        prepare_to_wait(&pasid_state->wq, &wait, TASK_UNINTERRUPTIBLE);
 
-       if (atomic_dec_and_test(&pasid_state->count))
-               put_device_state(pasid_state->device_state);
-       else
+       if (!atomic_dec_and_test(&pasid_state->count))
                schedule();
 
        finish_wait(&pasid_state->wq, &wait);
@@ -418,46 +407,21 @@ static void mn_invalidate_page(struct mmu_notifier *mn,
        __mn_flush_page(mn, address);
 }
 
-static void mn_invalidate_range_start(struct mmu_notifier *mn,
-                                     struct mm_struct *mm,
-                                     unsigned long start, unsigned long end)
-{
-       struct pasid_state *pasid_state;
-       struct device_state *dev_state;
-       unsigned long flags;
-
-       pasid_state = mn_to_state(mn);
-       dev_state   = pasid_state->device_state;
-
-       spin_lock_irqsave(&pasid_state->lock, flags);
-       if (pasid_state->mmu_notifier_count == 0) {
-               amd_iommu_domain_set_gcr3(dev_state->domain,
-                                         pasid_state->pasid,
-                                         __pa(empty_page_table));
-       }
-       pasid_state->mmu_notifier_count += 1;
-       spin_unlock_irqrestore(&pasid_state->lock, flags);
-}
-
-static void mn_invalidate_range_end(struct mmu_notifier *mn,
-                                   struct mm_struct *mm,
-                                   unsigned long start, unsigned long end)
+static void mn_invalidate_range(struct mmu_notifier *mn,
+                               struct mm_struct *mm,
+                               unsigned long start, unsigned long end)
 {
        struct pasid_state *pasid_state;
        struct device_state *dev_state;
-       unsigned long flags;
 
        pasid_state = mn_to_state(mn);
        dev_state   = pasid_state->device_state;
 
-       spin_lock_irqsave(&pasid_state->lock, flags);
-       pasid_state->mmu_notifier_count -= 1;
-       if (pasid_state->mmu_notifier_count == 0) {
-               amd_iommu_domain_set_gcr3(dev_state->domain,
-                                         pasid_state->pasid,
-                                         __pa(pasid_state->mm->pgd));
-       }
-       spin_unlock_irqrestore(&pasid_state->lock, flags);
+       if ((start ^ (end - 1)) < PAGE_SIZE)
+               amd_iommu_flush_page(dev_state->domain, pasid_state->pasid,
+                                    start);
+       else
+               amd_iommu_flush_tlb(dev_state->domain, pasid_state->pasid);
 }
 
 static void mn_release(struct mmu_notifier *mn, struct mm_struct *mm)
@@ -482,8 +446,7 @@ static struct mmu_notifier_ops iommu_mn = {
        .release                = mn_release,
        .clear_flush_young      = mn_clear_flush_young,
        .invalidate_page        = mn_invalidate_page,
-       .invalidate_range_start = mn_invalidate_range_start,
-       .invalidate_range_end   = mn_invalidate_range_end,
+       .invalidate_range       = mn_invalidate_range,
 };
 
 static void set_pri_tag_status(struct pasid_state *pasid_state,
@@ -954,18 +917,10 @@ static int __init amd_iommu_v2_init(void)
        if (iommu_wq == NULL)
                goto out;
 
-       ret = -ENOMEM;
-       empty_page_table = (u64 *)get_zeroed_page(GFP_KERNEL);
-       if (empty_page_table == NULL)
-               goto out_destroy_wq;
-
        amd_iommu_register_ppr_notifier(&ppr_nb);
 
        return 0;
 
-out_destroy_wq:
-       destroy_workqueue(iommu_wq);
-
 out:
        return ret;
 }
@@ -999,8 +954,6 @@ static void __exit amd_iommu_v2_exit(void)
        }
 
        destroy_workqueue(iommu_wq);
-
-       free_page((unsigned long)empty_page_table);
 }
 
 module_init(amd_iommu_v2_init);
index 6ae3cdee0681a8008218fbcf25762280b64e48ce..cc4f9d80122ea618e7543f4885843359194770a7 100644 (file)
@@ -217,8 +217,9 @@ struct irq_domain *__init aic_common_of_init(struct device_node *node,
        }
 
        ret = irq_alloc_domain_generic_chips(domain, 32, 1, name,
-                                            handle_level_irq, 0, 0,
-                                            IRQCHIP_SKIP_SET_WAKE);
+                                            handle_fasteoi_irq,
+                                            IRQ_NOREQUEST | IRQ_NOPROBE |
+                                            IRQ_NOAUTOEN, 0, 0);
        if (ret)
                goto err_domain_remove;
 
@@ -230,7 +231,6 @@ struct irq_domain *__init aic_common_of_init(struct device_node *node,
                gc->unused = 0;
                gc->wake_enabled = ~0;
                gc->chip_types[0].type = IRQ_TYPE_SENSE_MASK;
-               gc->chip_types[0].handler = handle_fasteoi_irq;
                gc->chip_types[0].chip.irq_eoi = irq_gc_eoi;
                gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake;
                gc->chip_types[0].chip.irq_shutdown = aic_common_shutdown;
index b9f4fb808e49a4afefa0bf66c707dbc01d7c3fa2..5fb38a2ac2261ca06c5bb338ae044a9ed61dc361 100644 (file)
@@ -101,9 +101,9 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn,
        int parent_irq;
 
        parent_irq = irq_of_parse_and_map(dn, irq);
-       if (parent_irq < 0) {
+       if (!parent_irq) {
                pr_err("failed to map interrupt %d\n", irq);
-               return parent_irq;
+               return -EINVAL;
        }
 
        data->irq_map_mask |= be32_to_cpup(map_mask + irq);
index c15c840987d2808e82cf1b056c231005933c5f8b..14691a4cb84cdf82fb38eefc0081a07460efae7b 100644 (file)
@@ -135,9 +135,9 @@ int __init brcmstb_l2_intc_of_init(struct device_node *np,
        __raw_writel(0xffffffff, data->base + CPU_CLEAR);
 
        data->parent_irq = irq_of_parse_and_map(np, 0);
-       if (data->parent_irq < 0) {
+       if (!data->parent_irq) {
                pr_err("failed to find parent interrupt\n");
-               ret = data->parent_irq;
+               ret = -EINVAL;
                goto out_unmap;
        }
 
index c9ac06cfe6b7b3a8f62568b70a6ad6d7ca9b44d0..a5115fb7cf331b9c39ed19a0b53d1ff527739295 100644 (file)
@@ -2471,7 +2471,8 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
                        bond_slave_state_change(bond);
                        if (BOND_MODE(bond) == BOND_MODE_XOR)
                                bond_update_slave_arr(bond, NULL);
-               } else if (do_failover) {
+               }
+               if (do_failover) {
                        block_netpoll_tx();
                        bond_select_active_slave(bond);
                        unblock_netpoll_tx();
index 02492d241e4c9e8cb8d49ae319067c7c0aa1f9cf..2cfe5012e4e58c3c4c51b968fba5c9c029e0db44 100644 (file)
@@ -110,7 +110,7 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
        long rate;
        u64 v64;
 
-       /* Use CIA recommended sample points */
+       /* Use CiA recommended sample points */
        if (bt->sample_point) {
                sampl_pt = bt->sample_point;
        } else {
@@ -382,7 +382,7 @@ void can_free_echo_skb(struct net_device *dev, unsigned int idx)
        BUG_ON(idx >= priv->echo_skb_max);
 
        if (priv->echo_skb[idx]) {
-               kfree_skb(priv->echo_skb[idx]);
+               dev_kfree_skb_any(priv->echo_skb[idx]);
                priv->echo_skb[idx] = NULL;
        }
 }
index fca5482c09acd43237f85e69765d3e66b96a4b86..04f20dd39007a105e329cb0168732cd8e909fd5d 100644 (file)
@@ -1,4 +1,5 @@
 config CAN_M_CAN
+       depends on HAS_IOMEM
        tristate "Bosch M_CAN devices"
        ---help---
          Say Y here if you want to support for Bosch M_CAN controller.
index 10d571eaed856814928151da898bd2053d4d899c..d7bc462aafdc27a26774aa6cb6cadb0e0d8547a3 100644 (file)
@@ -105,14 +105,36 @@ enum m_can_mram_cfg {
        MRAM_CFG_NUM,
 };
 
+/* Fast Bit Timing & Prescaler Register (FBTP) */
+#define FBTR_FBRP_MASK         0x1f
+#define FBTR_FBRP_SHIFT                16
+#define FBTR_FTSEG1_SHIFT      8
+#define FBTR_FTSEG1_MASK       (0xf << FBTR_FTSEG1_SHIFT)
+#define FBTR_FTSEG2_SHIFT      4
+#define FBTR_FTSEG2_MASK       (0x7 << FBTR_FTSEG2_SHIFT)
+#define FBTR_FSJW_SHIFT                0
+#define FBTR_FSJW_MASK         0x3
+
 /* Test Register (TEST) */
 #define TEST_LBCK      BIT(4)
 
 /* CC Control Register(CCCR) */
-#define CCCR_TEST      BIT(7)
-#define CCCR_MON       BIT(5)
-#define CCCR_CCE       BIT(1)
-#define CCCR_INIT      BIT(0)
+#define CCCR_TEST              BIT(7)
+#define CCCR_CMR_MASK          0x3
+#define CCCR_CMR_SHIFT         10
+#define CCCR_CMR_CANFD         0x1
+#define CCCR_CMR_CANFD_BRS     0x2
+#define CCCR_CMR_CAN           0x3
+#define CCCR_CME_MASK          0x3
+#define CCCR_CME_SHIFT         8
+#define CCCR_CME_CAN           0
+#define CCCR_CME_CANFD         0x1
+#define CCCR_CME_CANFD_BRS     0x2
+#define CCCR_TEST              BIT(7)
+#define CCCR_MON               BIT(5)
+#define CCCR_CCE               BIT(1)
+#define CCCR_INIT              BIT(0)
+#define CCCR_CANFD             0x10
 
 /* Bit Timing & Prescaler Register (BTP) */
 #define BTR_BRP_MASK           0x3ff
@@ -204,6 +226,7 @@ enum m_can_mram_cfg {
 
 /* Rx Buffer / FIFO Element Size Configuration (RXESC) */
 #define M_CAN_RXESC_8BYTES     0x0
+#define M_CAN_RXESC_64BYTES    0x777
 
 /* Tx Buffer Configuration(TXBC) */
 #define TXBC_NDTB_OFF          16
@@ -211,6 +234,7 @@ enum m_can_mram_cfg {
 
 /* Tx Buffer Element Size Configuration(TXESC) */
 #define TXESC_TBDS_8BYTES      0x0
+#define TXESC_TBDS_64BYTES     0x7
 
 /* Tx Event FIFO Con.guration (TXEFC) */
 #define TXEFC_EFS_OFF          16
@@ -219,11 +243,11 @@ enum m_can_mram_cfg {
 /* Message RAM Configuration (in bytes) */
 #define SIDF_ELEMENT_SIZE      4
 #define XIDF_ELEMENT_SIZE      8
-#define RXF0_ELEMENT_SIZE      16
-#define RXF1_ELEMENT_SIZE      16
+#define RXF0_ELEMENT_SIZE      72
+#define RXF1_ELEMENT_SIZE      72
 #define RXB_ELEMENT_SIZE       16
 #define TXE_ELEMENT_SIZE       8
-#define TXB_ELEMENT_SIZE       16
+#define TXB_ELEMENT_SIZE       72
 
 /* Message RAM Elements */
 #define M_CAN_FIFO_ID          0x0
@@ -231,11 +255,17 @@ enum m_can_mram_cfg {
 #define M_CAN_FIFO_DATA(n)     (0x8 + ((n) << 2))
 
 /* Rx Buffer Element */
+/* R0 */
 #define RX_BUF_ESI             BIT(31)
 #define RX_BUF_XTD             BIT(30)
 #define RX_BUF_RTR             BIT(29)
+/* R1 */
+#define RX_BUF_ANMF            BIT(31)
+#define RX_BUF_EDL             BIT(21)
+#define RX_BUF_BRS             BIT(20)
 
 /* Tx Buffer Element */
+/* R0 */
 #define TX_BUF_XTD             BIT(30)
 #define TX_BUF_RTR             BIT(29)
 
@@ -296,6 +326,7 @@ static inline void m_can_config_endisable(const struct m_can_priv *priv,
        if (enable) {
                /* enable m_can configuration */
                m_can_write(priv, M_CAN_CCCR, cccr | CCCR_INIT);
+               udelay(5);
                /* CCCR.CCE can only be set/reset while CCCR.INIT = '1' */
                m_can_write(priv, M_CAN_CCCR, cccr | CCCR_INIT | CCCR_CCE);
        } else {
@@ -326,41 +357,67 @@ static inline void m_can_disable_all_interrupts(const struct m_can_priv *priv)
        m_can_write(priv, M_CAN_ILE, 0x0);
 }
 
-static void m_can_read_fifo(const struct net_device *dev, struct can_frame *cf,
-                           u32 rxfs)
+static void m_can_read_fifo(struct net_device *dev, u32 rxfs)
 {
+       struct net_device_stats *stats = &dev->stats;
        struct m_can_priv *priv = netdev_priv(dev);
-       u32 id, fgi;
+       struct canfd_frame *cf;
+       struct sk_buff *skb;
+       u32 id, fgi, dlc;
+       int i;
 
        /* calculate the fifo get index for where to read data */
        fgi = (rxfs & RXFS_FGI_MASK) >> RXFS_FGI_OFF;
+       dlc = m_can_fifo_read(priv, fgi, M_CAN_FIFO_DLC);
+       if (dlc & RX_BUF_EDL)
+               skb = alloc_canfd_skb(dev, &cf);
+       else
+               skb = alloc_can_skb(dev, (struct can_frame **)&cf);
+       if (!skb) {
+               stats->rx_dropped++;
+               return;
+       }
+
+       if (dlc & RX_BUF_EDL)
+               cf->len = can_dlc2len((dlc >> 16) & 0x0F);
+       else
+               cf->len = get_can_dlc((dlc >> 16) & 0x0F);
+
        id = m_can_fifo_read(priv, fgi, M_CAN_FIFO_ID);
        if (id & RX_BUF_XTD)
                cf->can_id = (id & CAN_EFF_MASK) | CAN_EFF_FLAG;
        else
                cf->can_id = (id >> 18) & CAN_SFF_MASK;
 
-       if (id & RX_BUF_RTR) {
+       if (id & RX_BUF_ESI) {
+               cf->flags |= CANFD_ESI;
+               netdev_dbg(dev, "ESI Error\n");
+       }
+
+       if (!(dlc & RX_BUF_EDL) && (id & RX_BUF_RTR)) {
                cf->can_id |= CAN_RTR_FLAG;
        } else {
-               id = m_can_fifo_read(priv, fgi, M_CAN_FIFO_DLC);
-               cf->can_dlc = get_can_dlc((id >> 16) & 0x0F);
-               *(u32 *)(cf->data + 0) = m_can_fifo_read(priv, fgi,
-                                                        M_CAN_FIFO_DATA(0));
-               *(u32 *)(cf->data + 4) = m_can_fifo_read(priv, fgi,
-                                                        M_CAN_FIFO_DATA(1));
+               if (dlc & RX_BUF_BRS)
+                       cf->flags |= CANFD_BRS;
+
+               for (i = 0; i < cf->len; i += 4)
+                       *(u32 *)(cf->data + i) =
+                               m_can_fifo_read(priv, fgi,
+                                               M_CAN_FIFO_DATA(i / 4));
        }
 
        /* acknowledge rx fifo 0 */
        m_can_write(priv, M_CAN_RXF0A, fgi);
+
+       stats->rx_packets++;
+       stats->rx_bytes += cf->len;
+
+       netif_receive_skb(skb);
 }
 
 static int m_can_do_rx_poll(struct net_device *dev, int quota)
 {
        struct m_can_priv *priv = netdev_priv(dev);
-       struct net_device_stats *stats = &dev->stats;
-       struct sk_buff *skb;
-       struct can_frame *frame;
        u32 pkts = 0;
        u32 rxfs;
 
@@ -374,18 +431,7 @@ static int m_can_do_rx_poll(struct net_device *dev, int quota)
                if (rxfs & RXFS_RFL)
                        netdev_warn(dev, "Rx FIFO 0 Message Lost\n");
 
-               skb = alloc_can_skb(dev, &frame);
-               if (!skb) {
-                       stats->rx_dropped++;
-                       return pkts;
-               }
-
-               m_can_read_fifo(dev, frame, rxfs);
-
-               stats->rx_packets++;
-               stats->rx_bytes += frame->can_dlc;
-
-               netif_receive_skb(skb);
+               m_can_read_fifo(dev, rxfs);
 
                quota--;
                pkts++;
@@ -481,11 +527,23 @@ static int m_can_handle_lec_err(struct net_device *dev,
        return 1;
 }
 
+static int __m_can_get_berr_counter(const struct net_device *dev,
+                                   struct can_berr_counter *bec)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       unsigned int ecr;
+
+       ecr = m_can_read(priv, M_CAN_ECR);
+       bec->rxerr = (ecr & ECR_REC_MASK) >> ECR_REC_SHIFT;
+       bec->txerr = ecr & ECR_TEC_MASK;
+
+       return 0;
+}
+
 static int m_can_get_berr_counter(const struct net_device *dev,
                                  struct can_berr_counter *bec)
 {
        struct m_can_priv *priv = netdev_priv(dev);
-       unsigned int ecr;
        int err;
 
        err = clk_prepare_enable(priv->hclk);
@@ -498,9 +556,7 @@ static int m_can_get_berr_counter(const struct net_device *dev,
                return err;
        }
 
-       ecr = m_can_read(priv, M_CAN_ECR);
-       bec->rxerr = (ecr & ECR_REC_MASK) >> ECR_REC_SHIFT;
-       bec->txerr = ecr & ECR_TEC_MASK;
+       __m_can_get_berr_counter(dev, bec);
 
        clk_disable_unprepare(priv->cclk);
        clk_disable_unprepare(priv->hclk);
@@ -544,7 +600,7 @@ static int m_can_handle_state_change(struct net_device *dev,
        if (unlikely(!skb))
                return 0;
 
-       m_can_get_berr_counter(dev, &bec);
+       __m_can_get_berr_counter(dev, &bec);
 
        switch (new_state) {
        case CAN_STATE_ERROR_ACTIVE:
@@ -596,14 +652,14 @@ static int m_can_handle_state_errors(struct net_device *dev, u32 psr)
 
        if ((psr & PSR_EP) &&
            (priv->can.state != CAN_STATE_ERROR_PASSIVE)) {
-               netdev_dbg(dev, "entered error warning state\n");
+               netdev_dbg(dev, "entered error passive state\n");
                work_done += m_can_handle_state_change(dev,
                                                       CAN_STATE_ERROR_PASSIVE);
        }
 
        if ((psr & PSR_BO) &&
            (priv->can.state != CAN_STATE_BUS_OFF)) {
-               netdev_dbg(dev, "entered error warning state\n");
+               netdev_dbg(dev, "entered error bus off state\n");
                work_done += m_can_handle_state_change(dev,
                                                       CAN_STATE_BUS_OFF);
        }
@@ -615,7 +671,7 @@ static void m_can_handle_other_err(struct net_device *dev, u32 irqstatus)
 {
        if (irqstatus & IR_WDI)
                netdev_err(dev, "Message RAM Watchdog event due to missing READY\n");
-       if (irqstatus & IR_BEU)
+       if (irqstatus & IR_ELO)
                netdev_err(dev, "Error Logging Overflow\n");
        if (irqstatus & IR_BEU)
                netdev_err(dev, "Bit Error Uncorrected\n");
@@ -733,10 +789,23 @@ static const struct can_bittiming_const m_can_bittiming_const = {
        .brp_inc = 1,
 };
 
+static const struct can_bittiming_const m_can_data_bittiming_const = {
+       .name = KBUILD_MODNAME,
+       .tseg1_min = 2,         /* Time segment 1 = prop_seg + phase_seg1 */
+       .tseg1_max = 16,
+       .tseg2_min = 1,         /* Time segment 2 = phase_seg2 */
+       .tseg2_max = 8,
+       .sjw_max = 4,
+       .brp_min = 1,
+       .brp_max = 32,
+       .brp_inc = 1,
+};
+
 static int m_can_set_bittiming(struct net_device *dev)
 {
        struct m_can_priv *priv = netdev_priv(dev);
        const struct can_bittiming *bt = &priv->can.bittiming;
+       const struct can_bittiming *dbt = &priv->can.data_bittiming;
        u16 brp, sjw, tseg1, tseg2;
        u32 reg_btp;
 
@@ -747,7 +816,17 @@ static int m_can_set_bittiming(struct net_device *dev)
        reg_btp = (brp << BTR_BRP_SHIFT) | (sjw << BTR_SJW_SHIFT) |
                        (tseg1 << BTR_TSEG1_SHIFT) | (tseg2 << BTR_TSEG2_SHIFT);
        m_can_write(priv, M_CAN_BTP, reg_btp);
-       netdev_dbg(dev, "setting BTP 0x%x\n", reg_btp);
+
+       if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+               brp = dbt->brp - 1;
+               sjw = dbt->sjw - 1;
+               tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
+               tseg2 = dbt->phase_seg2 - 1;
+               reg_btp = (brp << FBTR_FBRP_SHIFT) | (sjw << FBTR_FSJW_SHIFT) |
+                               (tseg1 << FBTR_FTSEG1_SHIFT) |
+                               (tseg2 << FBTR_FTSEG2_SHIFT);
+               m_can_write(priv, M_CAN_FBTP, reg_btp);
+       }
 
        return 0;
 }
@@ -767,8 +846,8 @@ static void m_can_chip_config(struct net_device *dev)
 
        m_can_config_endisable(priv, true);
 
-       /* RX Buffer/FIFO Element Size 8 bytes data field */
-       m_can_write(priv, M_CAN_RXESC, M_CAN_RXESC_8BYTES);
+       /* RX Buffer/FIFO Element Size 64 bytes data field */
+       m_can_write(priv, M_CAN_RXESC, M_CAN_RXESC_64BYTES);
 
        /* Accept Non-matching Frames Into FIFO 0 */
        m_can_write(priv, M_CAN_GFC, 0x0);
@@ -777,8 +856,8 @@ static void m_can_chip_config(struct net_device *dev)
        m_can_write(priv, M_CAN_TXBC, (1 << TXBC_NDTB_OFF) |
                    priv->mcfg[MRAM_TXB].off);
 
-       /* only support 8 bytes firstly */
-       m_can_write(priv, M_CAN_TXESC, TXESC_TBDS_8BYTES);
+       /* support 64 bytes payload */
+       m_can_write(priv, M_CAN_TXESC, TXESC_TBDS_64BYTES);
 
        m_can_write(priv, M_CAN_TXEFC, (1 << TXEFC_EFS_OFF) |
                    priv->mcfg[MRAM_TXE].off);
@@ -793,7 +872,8 @@ static void m_can_chip_config(struct net_device *dev)
                    RXFC_FWM_1 | priv->mcfg[MRAM_RXF1].off);
 
        cccr = m_can_read(priv, M_CAN_CCCR);
-       cccr &= ~(CCCR_TEST | CCCR_MON);
+       cccr &= ~(CCCR_TEST | CCCR_MON | (CCCR_CMR_MASK << CCCR_CMR_SHIFT) |
+               (CCCR_CME_MASK << CCCR_CME_SHIFT));
        test = m_can_read(priv, M_CAN_TEST);
        test &= ~TEST_LBCK;
 
@@ -805,6 +885,9 @@ static void m_can_chip_config(struct net_device *dev)
                test |= TEST_LBCK;
        }
 
+       if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
+               cccr |= CCCR_CME_CANFD_BRS << CCCR_CME_SHIFT;
+
        m_can_write(priv, M_CAN_CCCR, cccr);
        m_can_write(priv, M_CAN_TEST, test);
 
@@ -869,11 +952,13 @@ static struct net_device *alloc_m_can_dev(void)
 
        priv->dev = dev;
        priv->can.bittiming_const = &m_can_bittiming_const;
+       priv->can.data_bittiming_const = &m_can_data_bittiming_const;
        priv->can.do_set_mode = m_can_set_mode;
        priv->can.do_get_berr_counter = m_can_get_berr_counter;
        priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
                                        CAN_CTRLMODE_LISTENONLY |
-                                       CAN_CTRLMODE_BERR_REPORTING;
+                                       CAN_CTRLMODE_BERR_REPORTING |
+                                       CAN_CTRLMODE_FD;
 
        return dev;
 }
@@ -956,8 +1041,9 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,
                                    struct net_device *dev)
 {
        struct m_can_priv *priv = netdev_priv(dev);
-       struct can_frame *cf = (struct can_frame *)skb->data;
-       u32 id;
+       struct canfd_frame *cf = (struct canfd_frame *)skb->data;
+       u32 id, cccr;
+       int i;
 
        if (can_dropped_invalid_skb(dev, skb))
                return NETDEV_TX_OK;
@@ -976,11 +1062,28 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,
 
        /* message ram configuration */
        m_can_fifo_write(priv, 0, M_CAN_FIFO_ID, id);
-       m_can_fifo_write(priv, 0, M_CAN_FIFO_DLC, cf->can_dlc << 16);
-       m_can_fifo_write(priv, 0, M_CAN_FIFO_DATA(0), *(u32 *)(cf->data + 0));
-       m_can_fifo_write(priv, 0, M_CAN_FIFO_DATA(1), *(u32 *)(cf->data + 4));
+       m_can_fifo_write(priv, 0, M_CAN_FIFO_DLC, can_len2dlc(cf->len) << 16);
+
+       for (i = 0; i < cf->len; i += 4)
+               m_can_fifo_write(priv, 0, M_CAN_FIFO_DATA(i / 4),
+                                *(u32 *)(cf->data + i));
+
        can_put_echo_skb(skb, dev, 0);
 
+       if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+               cccr = m_can_read(priv, M_CAN_CCCR);
+               cccr &= ~(CCCR_CMR_MASK << CCCR_CMR_SHIFT);
+               if (can_is_canfd_skb(skb)) {
+                       if (cf->flags & CANFD_BRS)
+                               cccr |= CCCR_CMR_CANFD_BRS << CCCR_CMR_SHIFT;
+                       else
+                               cccr |= CCCR_CMR_CANFD << CCCR_CMR_SHIFT;
+               } else {
+                       cccr |= CCCR_CMR_CAN << CCCR_CMR_SHIFT;
+               }
+               m_can_write(priv, M_CAN_CCCR, cccr);
+       }
+
        /* enable first TX buffer to start transfer  */
        m_can_write(priv, M_CAN_TXBTIE, 0x1);
        m_can_write(priv, M_CAN_TXBAR, 0x1);
@@ -992,6 +1095,7 @@ static const struct net_device_ops m_can_netdev_ops = {
        .ndo_open = m_can_open,
        .ndo_stop = m_can_close,
        .ndo_start_xmit = m_can_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 static int register_m_can_dev(struct net_device *dev)
@@ -1009,7 +1113,7 @@ static int m_can_of_parse_mram(struct platform_device *pdev,
        struct resource *res;
        void __iomem *addr;
        u32 out_val[MRAM_CFG_LEN];
-       int ret;
+       int i, start, end, ret;
 
        /* message ram could be shared */
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram");
@@ -1060,6 +1164,15 @@ static int m_can_of_parse_mram(struct platform_device *pdev,
                priv->mcfg[MRAM_TXE].off, priv->mcfg[MRAM_TXE].num,
                priv->mcfg[MRAM_TXB].off, priv->mcfg[MRAM_TXB].num);
 
+       /* initialize the entire Message RAM in use to avoid possible
+        * ECC/parity checksum errors when reading an uninitialized buffer
+        */
+       start = priv->mcfg[MRAM_SIDF].off;
+       end = priv->mcfg[MRAM_TXB].off +
+               priv->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE;
+       for (i = start; i < end; i += 4)
+               writel(0x0, priv->mram_base + i);
+
        return 0;
 }
 
index 1abe133d159428e0e098d611e8898bdaabb04c71..9718248e55f1e7c95c748b33538a4fb90a6f8d01 100644 (file)
@@ -628,6 +628,7 @@ static const struct net_device_ops rcar_can_netdev_ops = {
        .ndo_open = rcar_can_open,
        .ndo_stop = rcar_can_close,
        .ndo_start_xmit = rcar_can_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 static void rcar_can_rx_pkt(struct rcar_can_priv *priv)
index 8ff3424d51472bc1df5753c025c6cd73f9ab1ed0..15c00faeec61001ab02c22689709efb523a96eb0 100644 (file)
@@ -214,7 +214,7 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel,
        struct net_device *dev;
        struct sja1000_priv *priv;
        struct kvaser_pci *board;
-       int err, init_step;
+       int err;
 
        dev = alloc_sja1000dev(sizeof(struct kvaser_pci));
        if (dev == NULL)
@@ -235,7 +235,6 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel,
        if (channel == 0) {
                board->xilinx_ver =
                        ioread8(board->res_addr + XILINX_VERINT) >> 4;
-               init_step = 2;
 
                /* Assert PTADR# - we're in passive mode so the other bits are
                   not important */
@@ -264,8 +263,6 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel,
        priv->irq_flags = IRQF_SHARED;
        dev->irq = pdev->irq;
 
-       init_step = 4;
-
        dev_info(&pdev->dev, "reg_base=%p conf_addr=%p irq=%d\n",
                 priv->reg_base, board->conf_addr, dev->irq);
 
index 00f2534dde736f1dd8cda9b016bd6a78f79eeab0..29d3f0938eb836b4da53a0898f574ebf42721ae2 100644 (file)
@@ -434,10 +434,9 @@ static void ems_usb_read_bulk_callback(struct urb *urb)
        if (urb->actual_length > CPC_HEADER_SIZE) {
                struct ems_cpc_msg *msg;
                u8 *ibuf = urb->transfer_buffer;
-               u8 msg_count, again, start;
+               u8 msg_count, start;
 
                msg_count = ibuf[0] & ~0x80;
-               again = ibuf[0] & 0x80;
 
                start = CPC_HEADER_SIZE;
 
index b7c9e8b11460a3d6bd0e4fe7836f0e07e73eb586..c063a54ab8dd8a598f36e5a7e712722bb5931df1 100644 (file)
@@ -464,7 +464,6 @@ static void esd_usb2_write_bulk_callback(struct urb *urb)
 {
        struct esd_tx_urb_context *context = urb->context;
        struct esd_usb2_net_priv *priv;
-       struct esd_usb2 *dev;
        struct net_device *netdev;
        size_t size = sizeof(struct esd_usb2_msg);
 
@@ -472,7 +471,6 @@ static void esd_usb2_write_bulk_callback(struct urb *urb)
 
        priv = context->priv;
        netdev = priv->netdev;
-       dev = priv->usb2;
 
        /* free up our allocated buffer */
        usb_free_coherent(urb->dev, size,
@@ -1143,6 +1141,7 @@ static void esd_usb2_disconnect(struct usb_interface *intf)
                        }
                }
                unlink_all_urbs(dev);
+               kfree(dev);
        }
 }
 
index 04b0f84612f0cf12fd1cfc59925a60c448423fa2..009acc8641fc557cb580cb688983daf041519e4b 100644 (file)
@@ -718,6 +718,7 @@ static const struct net_device_ops gs_usb_netdev_ops = {
        .ndo_open = gs_can_open,
        .ndo_stop = gs_can_close,
        .ndo_start_xmit = gs_can_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 static struct gs_can *gs_make_candev(unsigned int channel, struct usb_interface *intf)
index 5e8b5609c067c53c2283a94dacd820fac8f1c565..8a998e3884ce0d502d9ebb19e7abde941ab85d3e 100644 (file)
@@ -300,7 +300,8 @@ static int xcan_set_bittiming(struct net_device *ndev)
 static int xcan_chip_start(struct net_device *ndev)
 {
        struct xcan_priv *priv = netdev_priv(ndev);
-       u32 err, reg_msr, reg_sr_mask;
+       u32 reg_msr, reg_sr_mask;
+       int err;
        unsigned long timeout;
 
        /* Check if it is in reset mode */
@@ -961,6 +962,7 @@ static const struct net_device_ops xcan_netdev_ops = {
        .ndo_open       = xcan_open,
        .ndo_stop       = xcan_close,
        .ndo_start_xmit = xcan_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 /**
index b9625968daacc0eb89c0f7371a3a4e70242f95ce..4f4c2a7888e5d74ee06ae58df8feaf5f1dea3123 100644 (file)
@@ -377,6 +377,29 @@ static irqreturn_t bcm_sf2_switch_1_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static int bcm_sf2_sw_rst(struct bcm_sf2_priv *priv)
+{
+       unsigned int timeout = 1000;
+       u32 reg;
+
+       reg = core_readl(priv, CORE_WATCHDOG_CTRL);
+       reg |= SOFTWARE_RESET | EN_CHIP_RST | EN_SW_RESET;
+       core_writel(priv, reg, CORE_WATCHDOG_CTRL);
+
+       do {
+               reg = core_readl(priv, CORE_WATCHDOG_CTRL);
+               if (!(reg & SOFTWARE_RESET))
+                       break;
+
+               usleep_range(1000, 2000);
+       } while (timeout-- > 0);
+
+       if (timeout == 0)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
 static int bcm_sf2_sw_setup(struct dsa_switch *ds)
 {
        const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
@@ -404,11 +427,18 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
                *base = of_iomap(dn, i);
                if (*base == NULL) {
                        pr_err("unable to find register: %s\n", reg_names[i]);
-                       return -ENODEV;
+                       ret = -ENOMEM;
+                       goto out_unmap;
                }
                base++;
        }
 
+       ret = bcm_sf2_sw_rst(priv);
+       if (ret) {
+               pr_err("unable to software reset switch: %d\n", ret);
+               goto out_unmap;
+       }
+
        /* Disable all interrupts and request them */
        intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
        intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
@@ -484,7 +514,8 @@ out_free_irq0:
 out_unmap:
        base = &priv->core;
        for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
-               iounmap(*base);
+               if (*base)
+                       iounmap(*base);
                base++;
        }
        return ret;
@@ -733,29 +764,6 @@ static int bcm_sf2_sw_suspend(struct dsa_switch *ds)
        return 0;
 }
 
-static int bcm_sf2_sw_rst(struct bcm_sf2_priv *priv)
-{
-       unsigned int timeout = 1000;
-       u32 reg;
-
-       reg = core_readl(priv, CORE_WATCHDOG_CTRL);
-       reg |= SOFTWARE_RESET | EN_CHIP_RST | EN_SW_RESET;
-       core_writel(priv, reg, CORE_WATCHDOG_CTRL);
-
-       do {
-               reg = core_readl(priv, CORE_WATCHDOG_CTRL);
-               if (!(reg & SOFTWARE_RESET))
-                       break;
-
-               usleep_range(1000, 2000);
-       } while (timeout-- > 0);
-
-       if (timeout == 0)
-               return -ETIMEDOUT;
-
-       return 0;
-}
-
 static int bcm_sf2_sw_resume(struct dsa_switch *ds)
 {
        struct bcm_sf2_priv *priv = ds_to_priv(ds);
index dbb41c1923e60cf1a152bf414ef3428c2d0f2167..77f8f836cbbe18a75d1ffa58fc61c077414eab5b 100644 (file)
@@ -8563,7 +8563,8 @@ static int tg3_init_rings(struct tg3 *tp)
                if (tnapi->rx_rcb)
                        memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp));
 
-               if (tg3_rx_prodring_alloc(tp, &tnapi->prodring)) {
+               if (tnapi->prodring.rx_std &&
+                   tg3_rx_prodring_alloc(tp, &tnapi->prodring)) {
                        tg3_free_rings(tp);
                        return -ENOMEM;
                }
index cca6049940037331911ba26bb5fe4c35b48e5059..4fe33606f372755efb2bcef46f28c68b7d763312 100644 (file)
@@ -1082,7 +1082,7 @@ static int cxgb4_cee_peer_getpg(struct net_device *dev, struct cee_pg *pg)
        pgid = be32_to_cpu(pcmd.u.dcb.pgid.pgid);
 
        for (i = 0; i < CXGB4_MAX_PRIORITY; i++)
-               pg->prio_pg[i] = (pgid >> (i * 4)) & 0xF;
+               pg->prio_pg[7 - i] = (pgid >> (i * 4)) & 0xF;
 
        INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
        pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;
index 9a18e7930b31bea1cebc533d014655af5673c748..597c463e384d0d5d9fb0f46a9b363e9c9165c6cf 100644 (file)
@@ -4309,11 +4309,16 @@ static int be_ndo_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh)
                return -EOPNOTSUPP;
 
        br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
+       if (!br_spec)
+               return -EINVAL;
 
        nla_for_each_nested(attr, br_spec, rem) {
                if (nla_type(attr) != IFLA_BRIDGE_MODE)
                        continue;
 
+               if (nla_len(attr) < sizeof(mode))
+                       return -EINVAL;
+
                mode = nla_get_u16(attr);
                if (mode != BRIDGE_MODE_VEPA && mode != BRIDGE_MODE_VEB)
                        return -EINVAL;
@@ -4421,6 +4426,11 @@ static void be_del_vxlan_port(struct net_device *netdev, sa_family_t sa_family,
                 "Disabled VxLAN offloads for UDP port %d\n",
                 be16_to_cpu(port));
 }
+
+static bool be_gso_check(struct sk_buff *skb, struct net_device *dev)
+{
+       return vxlan_gso_check(skb);
+}
 #endif
 
 static const struct net_device_ops be_netdev_ops = {
@@ -4450,6 +4460,7 @@ static const struct net_device_ops be_netdev_ops = {
 #ifdef CONFIG_BE2NET_VXLAN
        .ndo_add_vxlan_port     = be_add_vxlan_port,
        .ndo_del_vxlan_port     = be_del_vxlan_port,
+       .ndo_gso_check          = be_gso_check,
 #endif
 };
 
index a2d72a87cbde40465c16277e32d4a242a2873ee3..487cd9c4ac0d33a3ce07bb12fbe3f5db00e01586 100644 (file)
@@ -1012,7 +1012,8 @@ static void igb_free_q_vector(struct igb_adapter *adapter, int v_idx)
        /* igb_get_stats64() might access the rings on this vector,
         * we must wait a grace period before freeing it.
         */
-       kfree_rcu(q_vector, rcu);
+       if (q_vector)
+               kfree_rcu(q_vector, rcu);
 }
 
 /**
@@ -1792,8 +1793,10 @@ void igb_down(struct igb_adapter *adapter)
        adapter->flags &= ~IGB_FLAG_NEED_LINK_UPDATE;
 
        for (i = 0; i < adapter->num_q_vectors; i++) {
-               napi_synchronize(&(adapter->q_vector[i]->napi));
-               napi_disable(&(adapter->q_vector[i]->napi));
+               if (adapter->q_vector[i]) {
+                       napi_synchronize(&adapter->q_vector[i]->napi);
+                       napi_disable(&adapter->q_vector[i]->napi);
+               }
        }
 
 
@@ -3717,7 +3720,8 @@ static void igb_free_all_tx_resources(struct igb_adapter *adapter)
        int i;
 
        for (i = 0; i < adapter->num_tx_queues; i++)
-               igb_free_tx_resources(adapter->tx_ring[i]);
+               if (adapter->tx_ring[i])
+                       igb_free_tx_resources(adapter->tx_ring[i]);
 }
 
 void igb_unmap_and_free_tx_resource(struct igb_ring *ring,
@@ -3782,7 +3786,8 @@ static void igb_clean_all_tx_rings(struct igb_adapter *adapter)
        int i;
 
        for (i = 0; i < adapter->num_tx_queues; i++)
-               igb_clean_tx_ring(adapter->tx_ring[i]);
+               if (adapter->tx_ring[i])
+                       igb_clean_tx_ring(adapter->tx_ring[i]);
 }
 
 /**
@@ -3819,7 +3824,8 @@ static void igb_free_all_rx_resources(struct igb_adapter *adapter)
        int i;
 
        for (i = 0; i < adapter->num_rx_queues; i++)
-               igb_free_rx_resources(adapter->rx_ring[i]);
+               if (adapter->rx_ring[i])
+                       igb_free_rx_resources(adapter->rx_ring[i]);
 }
 
 /**
@@ -3874,7 +3880,8 @@ static void igb_clean_all_rx_rings(struct igb_adapter *adapter)
        int i;
 
        for (i = 0; i < adapter->num_rx_queues; i++)
-               igb_clean_rx_ring(adapter->rx_ring[i]);
+               if (adapter->rx_ring[i])
+                       igb_clean_rx_ring(adapter->rx_ring[i]);
 }
 
 /**
@@ -7404,6 +7411,8 @@ static int igb_resume(struct device *dev)
        pci_restore_state(pdev);
        pci_save_state(pdev);
 
+       if (!pci_device_is_present(pdev))
+               return -ENODEV;
        err = pci_enable_device_mem(pdev);
        if (err) {
                dev_err(&pdev->dev,
index d2df4e3d1032496dbf294f4d7b0b741ddfaac6d8..cc51554c9e99a49e74c24ab7bf8f97848a06d7a3 100644 (file)
@@ -3936,8 +3936,8 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
                 * if SR-IOV and VMDQ are disabled - otherwise ensure
                 * that hardware VLAN filters remain enabled.
                 */
-               if (!(adapter->flags & (IXGBE_FLAG_VMDQ_ENABLED |
-                                       IXGBE_FLAG_SRIOV_ENABLED)))
+               if (adapter->flags & (IXGBE_FLAG_VMDQ_ENABLED |
+                                     IXGBE_FLAG_SRIOV_ENABLED))
                        vlnctrl |= (IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN);
        } else {
                if (netdev->flags & IFF_ALLMULTI) {
@@ -7669,6 +7669,8 @@ static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
                return -EOPNOTSUPP;
 
        br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
+       if (!br_spec)
+               return -EINVAL;
 
        nla_for_each_nested(attr, br_spec, rem) {
                __u16 mode;
@@ -7677,6 +7679,9 @@ static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
                if (nla_type(attr) != IFLA_BRIDGE_MODE)
                        continue;
 
+               if (nla_len(attr) < sizeof(mode))
+                       return -EINVAL;
+
                mode = nla_get_u16(attr);
                if (mode == BRIDGE_MODE_VEPA) {
                        reg = 0;
@@ -7979,6 +7984,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        int i, err, pci_using_dac, expected_gts;
        unsigned int indices = MAX_TX_QUEUES;
        u8 part_str[IXGBE_PBANUM_LENGTH];
+       bool disable_dev = false;
 #ifdef IXGBE_FCOE
        u16 device_caps;
 #endif
@@ -8369,13 +8375,14 @@ err_sw_init:
        iounmap(adapter->io_addr);
        kfree(adapter->mac_table);
 err_ioremap:
+       disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state);
        free_netdev(netdev);
 err_alloc_etherdev:
        pci_release_selected_regions(pdev,
                                     pci_select_bars(pdev, IORESOURCE_MEM));
 err_pci_reg:
 err_dma:
-       if (!adapter || !test_and_set_bit(__IXGBE_DISABLED, &adapter->state))
+       if (!adapter || disable_dev)
                pci_disable_device(pdev);
        return err;
 }
@@ -8393,6 +8400,7 @@ static void ixgbe_remove(struct pci_dev *pdev)
 {
        struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
        struct net_device *netdev = adapter->netdev;
+       bool disable_dev;
 
        ixgbe_dbg_adapter_exit(adapter);
 
@@ -8442,11 +8450,12 @@ static void ixgbe_remove(struct pci_dev *pdev)
        e_dev_info("complete\n");
 
        kfree(adapter->mac_table);
+       disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state);
        free_netdev(netdev);
 
        pci_disable_pcie_error_reporting(pdev);
 
-       if (!test_and_set_bit(__IXGBE_DISABLED, &adapter->state))
+       if (disable_dev)
                pci_disable_device(pdev);
 }
 
index 02266e3de514f21c263ea91e9d3555475dc95099..4d69e382b4e5d07ab22fe327276c867099a12ca4 100644 (file)
@@ -1693,7 +1693,7 @@ int mlx4_en_start_port(struct net_device *dev)
        mlx4_set_stats_bitmap(mdev->dev, &priv->stats_bitmap);
 
 #ifdef CONFIG_MLX4_EN_VXLAN
-       if (priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS)
+       if (priv->mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN)
                vxlan_get_rx_port(dev);
 #endif
        priv->port_up = true;
@@ -2355,6 +2355,11 @@ static void mlx4_en_del_vxlan_port(struct  net_device *dev,
 
        queue_work(priv->mdev->workqueue, &priv->vxlan_del_task);
 }
+
+static bool mlx4_en_gso_check(struct sk_buff *skb, struct net_device *dev)
+{
+       return vxlan_gso_check(skb);
+}
 #endif
 
 static const struct net_device_ops mlx4_netdev_ops = {
@@ -2386,6 +2391,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
 #ifdef CONFIG_MLX4_EN_VXLAN
        .ndo_add_vxlan_port     = mlx4_en_add_vxlan_port,
        .ndo_del_vxlan_port     = mlx4_en_del_vxlan_port,
+       .ndo_gso_check          = mlx4_en_gso_check,
 #endif
 };
 
@@ -2416,6 +2422,11 @@ static const struct net_device_ops mlx4_netdev_ops_master = {
        .ndo_rx_flow_steer      = mlx4_en_filter_rfs,
 #endif
        .ndo_get_phys_port_id   = mlx4_en_get_phys_port_id,
+#ifdef CONFIG_MLX4_EN_VXLAN
+       .ndo_add_vxlan_port     = mlx4_en_add_vxlan_port,
+       .ndo_del_vxlan_port     = mlx4_en_del_vxlan_port,
+       .ndo_gso_check          = mlx4_en_gso_check,
+#endif
 };
 
 int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
index 5d2498dcf536d5e96cc13b9274b00137d4508c5d..cd5cf6d957c7afa98d76ad54ba42beb1b395e3c8 100644 (file)
@@ -1546,7 +1546,7 @@ static int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
 
        switch (op) {
        case RES_OP_RESERVE:
-               count = get_param_l(&in_param);
+               count = get_param_l(&in_param) & 0xffffff;
                align = get_param_h(&in_param);
                err = mlx4_grant_resource(dev, slave, RES_QP, count, 0);
                if (err)
index f5e29f7bdae39b77eed8abc0b8e73360ceeda698..a913b3ad2f899e791a9abd3c5e518d1f7410ceeb 100644 (file)
@@ -503,6 +503,11 @@ static void qlcnic_del_vxlan_port(struct net_device *netdev,
 
        adapter->flags |= QLCNIC_DEL_VXLAN_PORT;
 }
+
+static bool qlcnic_gso_check(struct sk_buff *skb, struct net_device *dev)
+{
+       return vxlan_gso_check(skb);
+}
 #endif
 
 static const struct net_device_ops qlcnic_netdev_ops = {
@@ -526,6 +531,7 @@ static const struct net_device_ops qlcnic_netdev_ops = {
 #ifdef CONFIG_QLCNIC_VXLAN
        .ndo_add_vxlan_port     = qlcnic_add_vxlan_port,
        .ndo_del_vxlan_port     = qlcnic_del_vxlan_port,
+       .ndo_gso_check          = qlcnic_gso_check,
 #endif
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller = qlcnic_poll_controller,
index db56fa7ce8f91ae816b4733c501f60504c2ae228..5b0da398621668402f06c64845fe44b9938d69ff 100644 (file)
@@ -177,12 +177,6 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
         */
        plat->maxmtu = JUMBO_LEN;
 
-       /* Set default value for multicast hash bins */
-       plat->multicast_filter_bins = HASH_TABLE_SIZE;
-
-       /* Set default value for unicast filter entries */
-       plat->unicast_filter_entries = 1;
-
        /*
         * Currently only the properties needed on SPEAr600
         * are provided. All other properties should be added
@@ -270,6 +264,13 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
                return PTR_ERR(addr);
 
        plat_dat = dev_get_platdata(&pdev->dev);
+
+       /* Set default value for multicast hash bins */
+       plat_dat->multicast_filter_bins = HASH_TABLE_SIZE;
+
+       /* Set default value for unicast filter entries */
+       plat_dat->unicast_filter_entries = 1;
+
        if (pdev->dev.of_node) {
                if (!plat_dat)
                        plat_dat = devm_kzalloc(&pdev->dev,
index d8794488f80a78cbc4171c7ac57d942eb36ab521..c560f9aeb55d691f23c65dae362c18defa1e9e44 100644 (file)
@@ -129,9 +129,9 @@ do {                                                                \
 #define CPSW_VLAN_AWARE                BIT(1)
 #define CPSW_ALE_VLAN_AWARE    1
 
-#define CPSW_FIFO_NORMAL_MODE          (0 << 15)
-#define CPSW_FIFO_DUAL_MAC_MODE                (1 << 15)
-#define CPSW_FIFO_RATE_LIMIT_MODE      (2 << 15)
+#define CPSW_FIFO_NORMAL_MODE          (0 << 16)
+#define CPSW_FIFO_DUAL_MAC_MODE                (1 << 16)
+#define CPSW_FIFO_RATE_LIMIT_MODE      (2 << 16)
 
 #define CPSW_INTPACEEN         (0x3f << 16)
 #define CPSW_INTPRESCALE_MASK  (0x7FF << 0)
index 9ce854f43917ad723da924e7a99e3629c6a6e9bd..6cbc56ad9ff49256fa218e87c031c5c9f371d17a 100644 (file)
@@ -377,17 +377,20 @@ static int ieee802154fake_probe(struct platform_device *pdev)
 
        err = wpan_phy_register(phy);
        if (err)
-               goto out;
+               goto err_phy_reg;
 
        err = register_netdev(dev);
-       if (err < 0)
-               goto out;
+       if (err)
+               goto err_netdev_reg;
 
        dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n");
        return 0;
 
-out:
-       unregister_netdev(dev);
+err_netdev_reg:
+       wpan_phy_unregister(phy);
+err_phy_reg:
+       free_netdev(dev);
+       wpan_phy_free(phy);
        return err;
 }
 
index 1aff970be33ec88ec8ff6781467155f68cf5b3b4..1dc628ffce2b52a565354f060dca84467d67e4b9 100644 (file)
@@ -506,7 +506,9 @@ static int pptp_getname(struct socket *sock, struct sockaddr *uaddr,
        int len = sizeof(struct sockaddr_pppox);
        struct sockaddr_pppox sp;
 
-       sp.sa_family      = AF_PPPOX;
+       memset(&sp.sa_addr, 0, sizeof(sp.sa_addr));
+
+       sp.sa_family    = AF_PPPOX;
        sp.sa_protocol  = PX_PROTO_PPTP;
        sp.sa_addr.pptp = pppox_sk(sock->sk)->proto.pptp.src_addr;
 
index 22756db53dcacc3138fd000cad8dbda968948fb8..b8a82b86f909095632c7d5747b9bf25cb81c970e 100644 (file)
@@ -780,6 +780,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x413c, 0x81a4, 8)},    /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
        {QMI_FIXED_INTF(0x413c, 0x81a8, 8)},    /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
        {QMI_FIXED_INTF(0x413c, 0x81a9, 8)},    /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
+       {QMI_FIXED_INTF(0x03f0, 0x581d, 4)},    /* HP lt4112 LTE/HSPA+ Gobi 4G Module (Huawei me906e) */
 
        /* 4. Gobi 1000 devices */
        {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},    /* Acer Gobi Modem Device */
index ec2a8b41ed41a1484c697f1897e0286f5d5d845a..b0bc8ead47de240c8f27605488eb300d0445c4fb 100644 (file)
@@ -1673,6 +1673,40 @@ static const struct attribute_group virtio_net_mrg_rx_group = {
 };
 #endif
 
+static bool virtnet_fail_on_feature(struct virtio_device *vdev,
+                                   unsigned int fbit,
+                                   const char *fname, const char *dname)
+{
+       if (!virtio_has_feature(vdev, fbit))
+               return false;
+
+       dev_err(&vdev->dev, "device advertises feature %s but not %s",
+               fname, dname);
+
+       return true;
+}
+
+#define VIRTNET_FAIL_ON(vdev, fbit, dbit)                      \
+       virtnet_fail_on_feature(vdev, fbit, #fbit, dbit)
+
+static bool virtnet_validate_features(struct virtio_device *vdev)
+{
+       if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ) &&
+           (VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_RX,
+                            "VIRTIO_NET_F_CTRL_VQ") ||
+            VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_VLAN,
+                            "VIRTIO_NET_F_CTRL_VQ") ||
+            VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE,
+                            "VIRTIO_NET_F_CTRL_VQ") ||
+            VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_MQ, "VIRTIO_NET_F_CTRL_VQ") ||
+            VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR,
+                            "VIRTIO_NET_F_CTRL_VQ"))) {
+               return false;
+       }
+
+       return true;
+}
+
 static int virtnet_probe(struct virtio_device *vdev)
 {
        int i, err;
@@ -1680,6 +1714,9 @@ static int virtnet_probe(struct virtio_device *vdev)
        struct virtnet_info *vi;
        u16 max_queue_pairs;
 
+       if (!virtnet_validate_features(vdev))
+               return -EINVAL;
+
        /* Find if host supports multiqueue virtio_net device */
        err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ,
                                   struct virtio_net_config,
index fa9dc45b75a6f9f7fb04e25c61fa3eb732d10af6..be4649a49c5e8bb2bec68aca08d27a82f5563d40 100644 (file)
 
 #define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */
 
-/* VXLAN protocol header */
-struct vxlanhdr {
-       __be32 vx_flags;
-       __be32 vx_vni;
-};
-
 /* UDP port for VXLAN traffic.
  * The IANA assigned port is 4789, but the Linux default is 8472
  * for compatibility with early adopters.
@@ -2312,9 +2306,9 @@ static struct socket *vxlan_create_sock(struct net *net, bool ipv6,
        if (ipv6) {
                udp_conf.family = AF_INET6;
                udp_conf.use_udp6_tx_checksums =
-                   !!(flags & VXLAN_F_UDP_ZERO_CSUM6_TX);
+                   !(flags & VXLAN_F_UDP_ZERO_CSUM6_TX);
                udp_conf.use_udp6_rx_checksums =
-                   !!(flags & VXLAN_F_UDP_ZERO_CSUM6_RX);
+                   !(flags & VXLAN_F_UDP_ZERO_CSUM6_RX);
        } else {
                udp_conf.family = AF_INET;
                udp_conf.local_ip.s_addr = INADDR_ANY;
index 697c4ae90af006f9c7f962bd21ea938af1892455..1e8ea5e4d4ca71ecd7598aea30d5a76f4749e85a 100644 (file)
@@ -664,6 +664,19 @@ static void ar9003_hw_override_ini(struct ath_hw *ah)
                ah->enabled_cals |= TX_CL_CAL;
        else
                ah->enabled_cals &= ~TX_CL_CAL;
+
+       if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah)) {
+               if (ah->is_clk_25mhz) {
+                       REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1);
+                       REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7);
+                       REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae);
+               } else {
+                       REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x261 << 1);
+                       REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400);
+                       REG_WRITE(ah, AR_SLP32_INC, 0x0001e800);
+               }
+               udelay(100);
+       }
 }
 
 static void ar9003_hw_prog_ini(struct ath_hw *ah,
index 8be4b145339426b7ea8a47a4788c9dd6be04b238..2ad605760e2136584a56c25680cb14324fa3d30c 100644 (file)
@@ -861,19 +861,6 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
        udelay(RTC_PLL_SETTLE_DELAY);
 
        REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
-
-       if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) {
-               if (ah->is_clk_25mhz) {
-                       REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1);
-                       REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7);
-                       REG_WRITE(ah,  AR_SLP32_INC, 0x0001e7ae);
-               } else {
-                       REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x261 << 1);
-                       REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400);
-                       REG_WRITE(ah,  AR_SLP32_INC, 0x0001e800);
-               }
-               udelay(100);
-       }
 }
 
 static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
index 30c66dfcd7a04b8489186c82db741b87f0afbad0..4f18a6be0c7d706092998c15bb290b3f6ddcdbc1 100644 (file)
@@ -974,9 +974,8 @@ void ath9k_calculate_iter_data(struct ath_softc *sc,
        struct ath_vif *avp;
 
        /*
-        * Pick the MAC address of the first interface as the new hardware
-        * MAC address. The hardware will use it together with the BSSID mask
-        * when matching addresses.
+        * The hardware will use primary station addr together with the
+        * BSSID mask when matching addresses.
         */
        memset(iter_data, 0, sizeof(*iter_data));
        memset(&iter_data->mask, 0xff, ETH_ALEN);
@@ -1205,6 +1204,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
                list_add_tail(&avp->list, &avp->chanctx->vifs);
        }
 
+       ath9k_calculate_summary_state(sc, avp->chanctx);
+
        ath9k_assign_hw_queues(hw, vif);
 
        an->sc = sc;
@@ -1274,6 +1275,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
 
        ath_tx_node_cleanup(sc, &avp->mcast_node);
 
+       ath9k_calculate_summary_state(sc, avp->chanctx);
+
        mutex_unlock(&sc->mutex);
 }
 
index 1dfc682a805513f5e5d160f6198f6d17bec644fc..ee27b06074e1213f68bb2e3f6bb632b61aeb5fd5 100644 (file)
@@ -300,9 +300,7 @@ void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
 
 void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg)
 {
-       assert_mac_suspended(dev);
-       dev->phy.ops->phy_write(dev, destreg,
-               dev->phy.ops->phy_read(dev, srcreg));
+       b43_phy_write(dev, destreg, b43_phy_read(dev, srcreg));
 }
 
 void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
index f05f5270fec1095df589b96490308bfe5193568a..927bffd5be6487125ca5f3e269b5eb0d690fb2f7 100644 (file)
@@ -40,8 +40,8 @@ void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
                return;
 
        irq = irq_of_parse_and_map(np, 0);
-       if (irq < 0) {
-               brcmf_err("interrupt could not be mapped: err=%d\n", irq);
+       if (!irq) {
+               brcmf_err("interrupt could not be mapped\n");
                devm_kfree(dev, sdiodev->pdata);
                return;
        }
index 8c0632ec9f7a6041e72a0a3c6e6243a00955d97f..16fef3382019192d90462835625011075b33a2ec 100644 (file)
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 #include <linux/delay.h>
-#include <linux/unaligned/access_ok.h>
 #include <linux/interrupt.h>
 #include <linux/bcma/bcma.h>
 #include <linux/sched.h>
+#include <asm/unaligned.h>
 
 #include <soc.h>
 #include <chipcommon.h>
index dc135915470d2cb70efab5480d11a036a0e00d3f..875d1142c8b0f5f65111a8674c7017a7e895721d 100644 (file)
@@ -669,10 +669,12 @@ static int brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,
                goto finalize;
        }
 
-       if (!brcmf_usb_ioctl_resp_wait(devinfo))
+       if (!brcmf_usb_ioctl_resp_wait(devinfo)) {
+               usb_kill_urb(devinfo->ctl_urb);
                ret = -ETIMEDOUT;
-       else
+       } else {
                memcpy(buffer, tmpbuf, buflen);
+       }
 
 finalize:
        kfree(tmpbuf);
index 28fa25b509db8c3154d2ff0220d4b05c5f83c99d..39b45c038a93ec2a538665bbe90498230493ec42 100644 (file)
@@ -299,6 +299,7 @@ static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
        primary_offset = ch->center_freq1 - ch->chan->center_freq;
        switch (ch->width) {
        case NL80211_CHAN_WIDTH_20:
+       case NL80211_CHAN_WIDTH_20_NOHT:
                ch_inf.bw = BRCMU_CHAN_BW_20;
                WARN_ON(primary_offset != 0);
                break;
@@ -323,6 +324,10 @@ static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
                                ch_inf.sb = BRCMU_CHAN_SB_LU;
                }
                break;
+       case NL80211_CHAN_WIDTH_80P80:
+       case NL80211_CHAN_WIDTH_160:
+       case NL80211_CHAN_WIDTH_5:
+       case NL80211_CHAN_WIDTH_10:
        default:
                WARN_ON_ONCE(1);
        }
@@ -333,6 +338,7 @@ static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
        case IEEE80211_BAND_5GHZ:
                ch_inf.band = BRCMU_CHAN_BAND_5G;
                break;
+       case IEEE80211_BAND_60GHZ:
        default:
                WARN_ON_ONCE(1);
        }
index 4f6e66892acc4658473aed57fc4c6cc72dd33fc4..b894a84e8393062a113102c8bbe96cf4b28f4f24 100644 (file)
@@ -155,6 +155,7 @@ enum iwl_ucode_tlv_api {
  * @IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests
  * @IWL_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA),
  *     which also implies support for the scheduler configuration command
+ * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command
  */
 enum iwl_ucode_tlv_capa {
        IWL_UCODE_TLV_CAPA_D0I3_SUPPORT                 = BIT(0),
@@ -163,6 +164,7 @@ enum iwl_ucode_tlv_capa {
        IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT       = BIT(10),
        IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT         = BIT(11),
        IWL_UCODE_TLV_CAPA_DQA_SUPPORT                  = BIT(12),
+       IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT              = BIT(18),
 };
 
 /* The default calibrate table size if not specified by firmware file */
index b62405865b25cd185c560731d54ab36304c54812..b6d2683da3a96dab9c53d0c6f291ab69de6e9e8f 100644 (file)
@@ -2448,9 +2448,15 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
 
        switch (vif->type) {
        case NL80211_IFTYPE_STATION:
-               /* Use aux roc framework (HS20) */
-               ret = iwl_mvm_send_aux_roc_cmd(mvm, channel,
-                                              vif, duration);
+               if (mvm->fw->ucode_capa.capa[0] &
+                   IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT) {
+                       /* Use aux roc framework (HS20) */
+                       ret = iwl_mvm_send_aux_roc_cmd(mvm, channel,
+                                                      vif, duration);
+                       goto out_unlock;
+               }
+               IWL_ERR(mvm, "hotspot not supported\n");
+               ret = -EINVAL;
                goto out_unlock;
        case NL80211_IFTYPE_P2P_DEVICE:
                /* handle below */
index b280d5d87127e87ea80f1eb36a477dad3dfcc6e2..7554f705383063fa3c7c3610595e9e39f0cc9af8 100644 (file)
@@ -602,16 +602,6 @@ static int iwl_mvm_cancel_regular_scan(struct iwl_mvm *mvm)
                                               SCAN_COMPLETE_NOTIFICATION };
        int ret;
 
-       if (mvm->scan_status == IWL_MVM_SCAN_NONE)
-               return 0;
-
-       if (iwl_mvm_is_radio_killed(mvm)) {
-               ieee80211_scan_completed(mvm->hw, true);
-               iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
-               mvm->scan_status = IWL_MVM_SCAN_NONE;
-               return 0;
-       }
-
        iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort,
                                   scan_abort_notif,
                                   ARRAY_SIZE(scan_abort_notif),
@@ -1400,6 +1390,16 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
 
 int iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
 {
+       if (mvm->scan_status == IWL_MVM_SCAN_NONE)
+               return 0;
+
+       if (iwl_mvm_is_radio_killed(mvm)) {
+               ieee80211_scan_completed(mvm->hw, true);
+               iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
+               mvm->scan_status = IWL_MVM_SCAN_NONE;
+               return 0;
+       }
+
        if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
                return iwl_mvm_scan_offload_stop(mvm, true);
        return iwl_mvm_cancel_regular_scan(mvm);
index 160c3ebc48d0b2c938c04718f5709407c7a2bc16..dd2f3f8baa9dbea639005b3b65dbbbda9109408f 100644 (file)
@@ -1894,8 +1894,7 @@ static u32 iwl_trans_pcie_dump_prph(struct iwl_trans *trans,
                int reg;
                __le32 *val;
 
-               prph_len += sizeof(*data) + sizeof(*prph) +
-                       num_bytes_in_chunk;
+               prph_len += sizeof(**data) + sizeof(*prph) + num_bytes_in_chunk;
 
                (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH);
                (*data)->len = cpu_to_le32(sizeof(*prph) +
index 8e68f87ab13c3081f062acc69fb71f59601e836f..66ff36447b9473799e27899bf44c3c3c8eb3994b 100644 (file)
@@ -158,55 +158,29 @@ void rt2x00queue_align_frame(struct sk_buff *skb)
        skb_trim(skb, frame_length);
 }
 
-void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)
+/*
+ * H/W needs L2 padding between the header and the paylod if header size
+ * is not 4 bytes aligned.
+ */
+void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int hdr_len)
 {
-       unsigned int payload_length = skb->len - header_length;
-       unsigned int header_align = ALIGN_SIZE(skb, 0);
-       unsigned int payload_align = ALIGN_SIZE(skb, header_length);
-       unsigned int l2pad = payload_length ? L2PAD_SIZE(header_length) : 0;
+       unsigned int l2pad = (skb->len > hdr_len) ? L2PAD_SIZE(hdr_len) : 0;
 
-       /*
-        * Adjust the header alignment if the payload needs to be moved more
-        * than the header.
-        */
-       if (payload_align > header_align)
-               header_align += 4;
-
-       /* There is nothing to do if no alignment is needed */
-       if (!header_align)
+       if (!l2pad)
                return;
 
-       /* Reserve the amount of space needed in front of the frame */
-       skb_push(skb, header_align);
-
-       /*
-        * Move the header.
-        */
-       memmove(skb->data, skb->data + header_align, header_length);
-
-       /* Move the payload, if present and if required */
-       if (payload_length && payload_align)
-               memmove(skb->data + header_length + l2pad,
-                       skb->data + header_length + l2pad + payload_align,
-                       payload_length);
-
-       /* Trim the skb to the correct size */
-       skb_trim(skb, header_length + l2pad + payload_length);
+       skb_push(skb, l2pad);
+       memmove(skb->data, skb->data + l2pad, hdr_len);
 }
 
-void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length)
+void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int hdr_len)
 {
-       /*
-        * L2 padding is only present if the skb contains more than just the
-        * IEEE 802.11 header.
-        */
-       unsigned int l2pad = (skb->len > header_length) ?
-                               L2PAD_SIZE(header_length) : 0;
+       unsigned int l2pad = (skb->len > hdr_len) ? L2PAD_SIZE(hdr_len) : 0;
 
        if (!l2pad)
                return;
 
-       memmove(skb->data + l2pad, skb->data, header_length);
+       memmove(skb->data + l2pad, skb->data, hdr_len);
        skb_pull(skb, l2pad);
 }
 
index 25daa8715219c6b89f110bb048cace12e3414159..846a2e6e34d855d62726eda65b51ee427bc1a939 100644 (file)
@@ -842,7 +842,8 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
                        break;
                }
                /* handle command packet here */
-               if (rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) {
+               if (rtlpriv->cfg->ops->rx_command_packet &&
+                   rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) {
                                dev_kfree_skb_any(skb);
                                goto end;
                }
@@ -1127,9 +1128,14 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
 
        __skb_queue_tail(&ring->queue, pskb);
 
-       rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, HW_DESC_OWN,
-                                   &temp_one);
-
+       if (rtlpriv->use_new_trx_flow) {
+               temp_one = 4;
+               rtlpriv->cfg->ops->set_desc(hw, (u8 *)pbuffer_desc, true,
+                                           HW_DESC_OWN, (u8 *)&temp_one);
+       } else {
+               rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, HW_DESC_OWN,
+                                           &temp_one);
+       }
        return;
 }
 
@@ -1370,9 +1376,9 @@ static void _rtl_pci_free_tx_ring(struct ieee80211_hw *hw,
        ring->desc = NULL;
        if (rtlpriv->use_new_trx_flow) {
                pci_free_consistent(rtlpci->pdev,
-                                   sizeof(*ring->desc) * ring->entries,
+                                   sizeof(*ring->buffer_desc) * ring->entries,
                                    ring->buffer_desc, ring->buffer_desc_dma);
-               ring->desc = NULL;
+               ring->buffer_desc = NULL;
        }
 }
 
@@ -1543,7 +1549,6 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
                                                         true,
                                                         HW_DESC_TXBUFF_ADDR),
                                                 skb->len, PCI_DMA_TODEVICE);
-                               ring->idx = (ring->idx + 1) % ring->entries;
                                kfree_skb(skb);
                                ring->idx = (ring->idx + 1) % ring->entries;
                        }
@@ -2244,6 +2249,16 @@ int rtl_pci_probe(struct pci_dev *pdev,
        /*like read eeprom and so on */
        rtlpriv->cfg->ops->read_eeprom_info(hw);
 
+       if (rtlpriv->cfg->ops->init_sw_vars(hw)) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Can't init_sw_vars\n");
+               err = -ENODEV;
+               goto fail3;
+       }
+       rtlpriv->cfg->ops->init_sw_leds(hw);
+
+       /*aspm */
+       rtl_pci_init_aspm(hw);
+
        /* Init mac80211 sw */
        err = rtl_init_core(hw);
        if (err) {
@@ -2259,16 +2274,6 @@ int rtl_pci_probe(struct pci_dev *pdev,
                goto fail3;
        }
 
-       if (rtlpriv->cfg->ops->init_sw_vars(hw)) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Can't init_sw_vars\n");
-               err = -ENODEV;
-               goto fail3;
-       }
-       rtlpriv->cfg->ops->init_sw_leds(hw);
-
-       /*aspm */
-       rtl_pci_init_aspm(hw);
-
        err = ieee80211_register_hw(hw);
        if (err) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
index 00e067044c08d0a9cafa9009466eb22c21965d56..5761d5b49e39e4e9cb2ce703f39578ad1cf99e74 100644 (file)
@@ -1201,6 +1201,9 @@ static int _rtl92se_set_media_status(struct ieee80211_hw *hw,
 
        }
 
+       if (type != NL80211_IFTYPE_AP &&
+           rtlpriv->mac80211.link_state < MAC80211_LINKED)
+               bt_msr = rtl_read_byte(rtlpriv, MSR) & ~MSR_LINK_MASK;
        rtl_write_byte(rtlpriv, (MSR), bt_msr);
 
        temp = rtl_read_dword(rtlpriv, TCR);
@@ -1262,6 +1265,7 @@ void rtl92se_enable_interrupt(struct ieee80211_hw *hw)
        rtl_write_dword(rtlpriv, INTA_MASK, rtlpci->irq_mask[0]);
        /* Support Bit 32-37(Assign as Bit 0-5) interrupt setting now */
        rtl_write_dword(rtlpriv, INTA_MASK + 4, rtlpci->irq_mask[1] & 0x3F);
+       rtlpci->irq_enabled = true;
 }
 
 void rtl92se_disable_interrupt(struct ieee80211_hw *hw)
@@ -1276,8 +1280,7 @@ void rtl92se_disable_interrupt(struct ieee80211_hw *hw)
        rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        rtl_write_dword(rtlpriv, INTA_MASK, 0);
        rtl_write_dword(rtlpriv, INTA_MASK + 4, 0);
-
-       synchronize_irq(rtlpci->pdev->irq);
+       rtlpci->irq_enabled = false;
 }
 
 static u8 _rtl92s_set_sysclk(struct ieee80211_hw *hw, u8 data)
index 77c5b5f352441a3a2a2d0c26b5627266aa15d5d9..4b4612fe2fdbdf318bad0b0a6e36873a6340d60b 100644 (file)
@@ -399,6 +399,8 @@ static bool _rtl92s_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
                case 2:
                        currentcmd = &postcommoncmd[*step];
                        break;
+               default:
+                       return true;
                }
 
                if (currentcmd->cmdid == CMDID_END) {
index aadba29c167aff4c8ddf38db610db3cdfcbfcd93..fb003868bdef7ed9bbb775042a380190ce68162d 100644 (file)
@@ -236,6 +236,19 @@ static void rtl92s_deinit_sw_vars(struct ieee80211_hw *hw)
        }
 }
 
+static bool rtl92se_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue,
+                                     u16 index)
+{
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
+       u8 *entry = (u8 *)(&ring->desc[ring->idx]);
+       u8 own = (u8)rtl92se_get_desc(entry, true, HW_DESC_OWN);
+
+       if (own)
+               return false;
+       return true;
+}
+
 static struct rtl_hal_ops rtl8192se_hal_ops = {
        .init_sw_vars = rtl92s_init_sw_vars,
        .deinit_sw_vars = rtl92s_deinit_sw_vars,
@@ -269,6 +282,7 @@ static struct rtl_hal_ops rtl8192se_hal_ops = {
        .led_control = rtl92se_led_control,
        .set_desc = rtl92se_set_desc,
        .get_desc = rtl92se_get_desc,
+       .is_tx_desc_closed = rtl92se_is_tx_desc_closed,
        .tx_polling = rtl92se_tx_polling,
        .enable_hw_sec = rtl92se_enable_hw_security_config,
        .set_key = rtl92se_set_key,
@@ -306,6 +320,8 @@ static struct rtl_hal_cfg rtl92se_hal_cfg = {
        .maps[MAC_RCR_ACRC32] = RCR_ACRC32,
        .maps[MAC_RCR_ACF] = RCR_ACF,
        .maps[MAC_RCR_AAP] = RCR_AAP,
+       .maps[MAC_HIMR] = INTA_MASK,
+       .maps[MAC_HIMRE] = INTA_MASK + 4,
 
        .maps[EFUSE_TEST] = REG_EFUSE_TEST,
        .maps[EFUSE_CTRL] = REG_EFUSE_CTRL,
index 310d3163dc5b6a3f1e51a9a59ed999fe991a2f06..8ec8200002c7311025b3ae645c9956bf08c44a17 100644 (file)
@@ -3672,8 +3672,9 @@ static void rtl8821ae_update_hal_rate_mask(struct ieee80211_hw *hw,
                mac->opmode == NL80211_IFTYPE_ADHOC)
                macid = sta->aid + 1;
        if (wirelessmode == WIRELESS_MODE_N_5G ||
-           wirelessmode == WIRELESS_MODE_AC_5G)
-               ratr_bitmap = sta->supp_rates[NL80211_BAND_5GHZ];
+           wirelessmode == WIRELESS_MODE_AC_5G ||
+           wirelessmode == WIRELESS_MODE_A)
+               ratr_bitmap = sta->supp_rates[NL80211_BAND_5GHZ] << 4;
        else
                ratr_bitmap = sta->supp_rates[NL80211_BAND_2GHZ];
 
index 4e56a27f9689a925ff3cf26118c6ee505eb963a4..fab0d4b42f58fca511dc447b62ea91607732ba81 100644 (file)
@@ -39,7 +39,7 @@ struct backend_info {
 static int connect_rings(struct backend_info *be, struct xenvif_queue *queue);
 static void connect(struct backend_info *be);
 static int read_xenbus_vif_flags(struct backend_info *be);
-static void backend_create_xenvif(struct backend_info *be);
+static int backend_create_xenvif(struct backend_info *be);
 static void unregister_hotplug_status_watch(struct backend_info *be);
 static void set_backend_state(struct backend_info *be,
                              enum xenbus_state state);
@@ -352,7 +352,9 @@ static int netback_probe(struct xenbus_device *dev,
        be->state = XenbusStateInitWait;
 
        /* This kicks hotplug scripts, so do it immediately. */
-       backend_create_xenvif(be);
+       err = backend_create_xenvif(be);
+       if (err)
+               goto fail;
 
        return 0;
 
@@ -397,19 +399,19 @@ static int netback_uevent(struct xenbus_device *xdev,
 }
 
 
-static void backend_create_xenvif(struct backend_info *be)
+static int backend_create_xenvif(struct backend_info *be)
 {
        int err;
        long handle;
        struct xenbus_device *dev = be->dev;
 
        if (be->vif != NULL)
-               return;
+               return 0;
 
        err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li", &handle);
        if (err != 1) {
                xenbus_dev_fatal(dev, err, "reading handle");
-               return;
+               return (err < 0) ? err : -EINVAL;
        }
 
        be->vif = xenvif_alloc(&dev->dev, dev->otherend_id, handle);
@@ -417,10 +419,11 @@ static void backend_create_xenvif(struct backend_info *be)
                err = PTR_ERR(be->vif);
                be->vif = NULL;
                xenbus_dev_fatal(dev, err, "creating interface");
-               return;
+               return err;
        }
 
        kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
+       return 0;
 }
 
 static void backend_disconnect(struct backend_info *be)
index afdb78299f61f8d5465ec1d203d482d0674fe31d..06af494184d657456df3c353b9e61e380ec98dec 100644 (file)
@@ -450,6 +450,21 @@ static struct of_bus *of_match_bus(struct device_node *np)
        return NULL;
 }
 
+static int of_empty_ranges_quirk(void)
+{
+       if (IS_ENABLED(CONFIG_PPC)) {
+               /* To save cycles, we cache the result */
+               static int quirk_state = -1;
+
+               if (quirk_state < 0)
+                       quirk_state =
+                               of_machine_is_compatible("Power Macintosh") ||
+                               of_machine_is_compatible("MacRISC");
+               return quirk_state;
+       }
+       return false;
+}
+
 static int of_translate_one(struct device_node *parent, struct of_bus *bus,
                            struct of_bus *pbus, __be32 *addr,
                            int na, int ns, int pna, const char *rprop)
@@ -475,12 +490,10 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
         * This code is only enabled on powerpc. --gcl
         */
        ranges = of_get_property(parent, rprop, &rlen);
-#if !defined(CONFIG_PPC)
-       if (ranges == NULL) {
+       if (ranges == NULL && !of_empty_ranges_quirk()) {
                pr_err("OF: no ranges; cannot translate\n");
                return 1;
        }
-#endif /* !defined(CONFIG_PPC) */
        if (ranges == NULL || rlen == 0) {
                offset = of_read_number(addr, na);
                memset(addr, 0, pna * 4);
index f297891d852908ae3e78fe9bfa2bfe5b231875e6..d4994177dec25506e454bf1556050ffc2754d084 100644 (file)
@@ -247,7 +247,7 @@ void of_node_release(struct kobject *kobj)
  * @allocflags:        Allocation flags (typically pass GFP_KERNEL)
  *
  * Copy a property by dynamically allocating the memory of both the
- * property stucture and the property name & contents. The property's
+ * property structure and the property name & contents. The property's
  * flags have the OF_DYNAMIC bit set so that we can differentiate between
  * dynamically allocated properties and not.
  * Returns the newly allocated property or NULL on out of memory error.
index d1ffca8b34eac51853c812a230cfd438862f8cff..30e97bcc4f88293ff902df937446d0983db6d4f3 100644 (file)
@@ -773,7 +773,7 @@ int __init early_init_dt_scan_chosen_serial(void)
        if (offset < 0)
                return -ENODEV;
 
-       while (match->compatible) {
+       while (match->compatible[0]) {
                unsigned long addr;
                if (fdt_node_check_compatible(fdt, offset, match->compatible)) {
                        match++;
index 11b873c54a776c5fd819d05875fce54b6d00f9ce..e2d79afa9dc6153613c4281570eb620332249c8c 100644 (file)
@@ -896,10 +896,14 @@ static void selftest_data_remove(void)
                return;
        }
 
-       while (last_node_index >= 0) {
+       while (last_node_index-- > 0) {
                if (nodes[last_node_index]) {
                        np = of_find_node_by_path(nodes[last_node_index]->full_name);
-                       if (strcmp(np->full_name, "/aliases") != 0) {
+                       if (np == nodes[last_node_index]) {
+                               if (of_aliases == np) {
+                                       of_node_put(of_aliases);
+                                       of_aliases = NULL;
+                               }
                                detach_node_and_children(np);
                        } else {
                                for_each_property_of_node(np, prop) {
@@ -908,7 +912,6 @@ static void selftest_data_remove(void)
                                }
                        }
                }
-               last_node_index--;
        }
 }
 
@@ -921,6 +924,8 @@ static int __init of_selftest(void)
        res = selftest_data_add();
        if (res)
                return res;
+       if (!of_aliases)
+               of_aliases = of_find_node_by_path("/aliases");
 
        np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
        if (!np) {
index d292d7cb3417062643379805a969f5d29718de2f..49dd766852ba58f5ebad21199e38f1e2a912b498 100644 (file)
@@ -444,7 +444,7 @@ static inline int pcie_cap_version(const struct pci_dev *dev)
        return pcie_caps_reg(dev) & PCI_EXP_FLAGS_VERS;
 }
 
-static inline bool pcie_cap_has_lnkctl(const struct pci_dev *dev)
+bool pcie_cap_has_lnkctl(const struct pci_dev *dev)
 {
        int type = pci_pcie_type(dev);
 
index 9ecabfa8c6343a83afba9d33b101bc4161b6bd3f..2988fe136c1e3ede0240e90db80d6e4e013e6e8a 100644 (file)
@@ -631,10 +631,15 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       bus = pci_scan_root_bus(&pdev->dev, 0, &xgene_pcie_ops, port, &res);
+       bus = pci_create_root_bus(&pdev->dev, 0,
+                                       &xgene_pcie_ops, port, &res);
        if (!bus)
                return -ENOMEM;
 
+       pci_scan_child_bus(bus);
+       pci_assign_unassigned_bus_resources(bus);
+       pci_bus_add_devices(bus);
+
        platform_set_drvdata(pdev, port);
        return 0;
 }
index 9fab30af0e75abdcec135707363951d7e9e26f8c..084587d7cd134ce0e8e20410368f5b60b9e88f74 100644 (file)
@@ -590,6 +590,20 @@ static struct msi_desc *msi_setup_entry(struct pci_dev *dev)
        return entry;
 }
 
+static int msi_verify_entries(struct pci_dev *dev)
+{
+       struct msi_desc *entry;
+
+       list_for_each_entry(entry, &dev->msi_list, list) {
+               if (!dev->no_64bit_msi || !entry->msg.address_hi)
+                       continue;
+               dev_err(&dev->dev, "Device has broken 64-bit MSI but arch"
+                       " tried to assign one above 4G\n");
+               return -EIO;
+       }
+       return 0;
+}
+
 /**
  * msi_capability_init - configure device's MSI capability structure
  * @dev: pointer to the pci_dev data structure of MSI device function
@@ -627,6 +641,13 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
                return ret;
        }
 
+       ret = msi_verify_entries(dev);
+       if (ret) {
+               msi_mask_irq(entry, mask, ~mask);
+               free_msi_irqs(dev);
+               return ret;
+       }
+
        ret = populate_msi_sysfs(dev);
        if (ret) {
                msi_mask_irq(entry, mask, ~mask);
@@ -739,6 +760,11 @@ static int msix_capability_init(struct pci_dev *dev,
        if (ret)
                goto out_avail;
 
+       /* Check if all MSI entries honor device restrictions */
+       ret = msi_verify_entries(dev);
+       if (ret)
+               goto out_free;
+
        /*
         * Some devices require MSI-X to be enabled before we can touch the
         * MSI-X registers.  We need to mask all the vectors to prevent
index 0601890db22de96131af2d67fd872651ab608133..4a3902d8e6fec7984bb483b55aee4115101cc1f4 100644 (file)
@@ -6,6 +6,8 @@
 
 extern const unsigned char pcie_link_speed[];
 
+bool pcie_cap_has_lnkctl(const struct pci_dev *dev);
+
 /* Functions internal to the PCI core code */
 
 int pci_create_sysfs_dev_files(struct pci_dev *pdev);
index 5ed99309c75800938b666c5c523d7ea3ca07d51f..c8ca98c2b480a41d57676ef21e97cd6612134110 100644 (file)
@@ -407,15 +407,16 @@ static void pci_read_bridge_mmio_pref(struct pci_bus *child)
 {
        struct pci_dev *dev = child->self;
        u16 mem_base_lo, mem_limit_lo;
-       unsigned long base, limit;
+       u64 base64, limit64;
+       dma_addr_t base, limit;
        struct pci_bus_region region;
        struct resource *res;
 
        res = child->resource[2];
        pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
        pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
-       base = ((unsigned long) mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
-       limit = ((unsigned long) mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
+       base64 = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
+       limit64 = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
 
        if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
                u32 mem_base_hi, mem_limit_hi;
@@ -429,17 +430,20 @@ static void pci_read_bridge_mmio_pref(struct pci_bus *child)
                 * this, just assume they are not being used.
                 */
                if (mem_base_hi <= mem_limit_hi) {
-#if BITS_PER_LONG == 64
-                       base |= ((unsigned long) mem_base_hi) << 32;
-                       limit |= ((unsigned long) mem_limit_hi) << 32;
-#else
-                       if (mem_base_hi || mem_limit_hi) {
-                               dev_err(&dev->dev, "can't handle 64-bit address space for bridge\n");
-                               return;
-                       }
-#endif
+                       base64 |= (u64) mem_base_hi << 32;
+                       limit64 |= (u64) mem_limit_hi << 32;
                }
        }
+
+       base = (dma_addr_t) base64;
+       limit = (dma_addr_t) limit64;
+
+       if (base != base64) {
+               dev_err(&dev->dev, "can't handle bridge window above 4GB (bus address %#010llx)\n",
+                       (unsigned long long) base64);
+               return;
+       }
+
        if (base <= limit) {
                res->flags = (mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) |
                                         IORESOURCE_MEM | IORESOURCE_PREFETCH;
@@ -1323,7 +1327,7 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
                        ~hpp->pci_exp_devctl_and, hpp->pci_exp_devctl_or);
 
        /* Initialize Link Control Register */
-       if (dev->subordinate)
+       if (pcie_cap_has_lnkctl(dev))
                pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL,
                        ~hpp->pci_exp_lnkctl_and, hpp->pci_exp_lnkctl_or);
 
index 79e5c94107a9cc44fe8269f55ab72e8150005e0b..72533c58c1f3bc0d6a18412a197651399abbf6a2 100644 (file)
@@ -412,6 +412,7 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev,
        struct fc_frame_header *fh;
        struct fcoe_rcv_info *fr;
        struct fcoe_percpu_s *bg;
+       struct sk_buff *tmp_skb;
        unsigned short oxid;
 
        interface = container_of(ptype, struct bnx2fc_interface,
@@ -424,6 +425,12 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev,
                goto err;
        }
 
+       tmp_skb = skb_share_check(skb, GFP_ATOMIC);
+       if (!tmp_skb)
+               goto err;
+
+       skb = tmp_skb;
+
        if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) {
                printk(KERN_ERR PFX "bnx2fc_rcv: Wrong FC type frame\n");
                goto err;
index 81bb3bd7909d711e2131f50a037bffc47cf70e8c..15081257cfc881d71e0638159dea1e58006f2769 100644 (file)
@@ -828,6 +828,8 @@ static void do_act_open_rpl(struct cxgbi_device *cdev, struct sk_buff *skb)
        if (status == CPL_ERR_RTX_NEG_ADVICE)
                goto rel_skb;
 
+       module_put(THIS_MODULE);
+
        if (status && status != CPL_ERR_TCAM_FULL &&
            status != CPL_ERR_CONN_EXIST &&
            status != CPL_ERR_ARP_MISS)
index 13d869a92248e8d31754fccebe0152dae859f570..7da59c38a69ec97cf15507876122151222e52fe1 100644 (file)
@@ -816,7 +816,7 @@ static void cxgbi_inform_iscsi_conn_closing(struct cxgbi_sock *csk)
                read_lock_bh(&csk->callback_lock);
                if (csk->user_data)
                        iscsi_conn_failure(csk->user_data,
-                                       ISCSI_ERR_CONN_FAILED);
+                                       ISCSI_ERR_TCP_CONN_CLOSE);
                read_unlock_bh(&csk->callback_lock);
        }
 }
index 49014a143c6a9ab56ec81a56d3c7180156341d95..c1d04d4d3c6c140457c19e50865b29bd3287d54f 100644 (file)
@@ -202,6 +202,7 @@ static struct {
        {"IOMEGA", "Io20S         *F", NULL, BLIST_KEY},
        {"INSITE", "Floptical   F*8I", NULL, BLIST_KEY},
        {"INSITE", "I325VM", NULL, BLIST_KEY},
+       {"Intel", "Multi-Flex", NULL, BLIST_NO_RSOC},
        {"iRiver", "iFP Mass Driver", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
        {"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
        {"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
index 8adf067ff019344eaf0c42b97007b4abac65e79e..1c3467b8256612b96bafaee3827312e21711de28 100644 (file)
@@ -102,7 +102,6 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
        clkfreq = devm_kzalloc(dev, sz * sizeof(*clkfreq),
                        GFP_KERNEL);
        if (!clkfreq) {
-               dev_err(dev, "%s: no memory\n", "freq-table-hz");
                ret = -ENOMEM;
                goto out;
        }
@@ -112,19 +111,19 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
        if (ret && (ret != -EINVAL)) {
                dev_err(dev, "%s: error reading array %d\n",
                                "freq-table-hz", ret);
-               goto free_clkfreq;
+               return ret;
        }
 
        for (i = 0; i < sz; i += 2) {
                ret = of_property_read_string_index(np,
                                "clock-names", i/2, (const char **)&name);
                if (ret)
-                       goto free_clkfreq;
+                       goto out;
 
                clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
                if (!clki) {
                        ret = -ENOMEM;
-                       goto free_clkfreq;
+                       goto out;
                }
 
                clki->min_freq = clkfreq[i];
@@ -134,8 +133,6 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
                                clki->min_freq, clki->max_freq, clki->name);
                list_add_tail(&clki->list, &hba->clk_list_head);
        }
-free_clkfreq:
-       kfree(clkfreq);
 out:
        return ret;
 }
@@ -162,10 +159,8 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name,
        }
 
        vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
-       if (!vreg) {
-               dev_err(dev, "No memory for %s regulator\n", name);
-               goto out;
-       }
+       if (!vreg)
+               return -ENOMEM;
 
        vreg->name = kstrdup(name, GFP_KERNEL);
 
index 497c38a4a86615178e367e40666937e2d969b41f..605ca60e8a10da25bed98f9d2ac6fdb42b13176f 100644 (file)
@@ -744,6 +744,8 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
        if (!ufshcd_is_clkgating_allowed(hba))
                return;
        device_remove_file(hba->dev, &hba->clk_gating.delay_attr);
+       cancel_work_sync(&hba->clk_gating.ungate_work);
+       cancel_delayed_work_sync(&hba->clk_gating.gate_work);
 }
 
 /* Must be called with host lock acquired */
@@ -2246,6 +2248,22 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
        return ret;
 }
 
+ /**
+ * ufshcd_init_pwr_info - setting the POR (power on reset)
+ * values in hba power info
+ * @hba: per-adapter instance
+ */
+static void ufshcd_init_pwr_info(struct ufs_hba *hba)
+{
+       hba->pwr_info.gear_rx = UFS_PWM_G1;
+       hba->pwr_info.gear_tx = UFS_PWM_G1;
+       hba->pwr_info.lane_rx = 1;
+       hba->pwr_info.lane_tx = 1;
+       hba->pwr_info.pwr_rx = SLOWAUTO_MODE;
+       hba->pwr_info.pwr_tx = SLOWAUTO_MODE;
+       hba->pwr_info.hs_rate = 0;
+}
+
 /**
  * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device
  * @hba: per-adapter instance
@@ -2844,8 +2862,13 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev)
        hba = shost_priv(sdev->host);
        scsi_deactivate_tcq(sdev, hba->nutrs);
        /* Drop the reference as it won't be needed anymore */
-       if (ufshcd_scsi_to_upiu_lun(sdev->lun) == UFS_UPIU_UFS_DEVICE_WLUN)
+       if (ufshcd_scsi_to_upiu_lun(sdev->lun) == UFS_UPIU_UFS_DEVICE_WLUN) {
+               unsigned long flags;
+
+               spin_lock_irqsave(hba->host->host_lock, flags);
                hba->sdev_ufs_device = NULL;
+               spin_unlock_irqrestore(hba->host->host_lock, flags);
+       }
 }
 
 /**
@@ -4062,6 +4085,8 @@ static void ufshcd_init_icc_levels(struct ufs_hba *hba)
 static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
 {
        int ret = 0;
+       struct scsi_device *sdev_rpmb;
+       struct scsi_device *sdev_boot;
 
        hba->sdev_ufs_device = __scsi_add_device(hba->host, 0, 0,
                ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN), NULL);
@@ -4070,56 +4095,33 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
                hba->sdev_ufs_device = NULL;
                goto out;
        }
+       scsi_device_put(hba->sdev_ufs_device);
 
-       hba->sdev_boot = __scsi_add_device(hba->host, 0, 0,
+       sdev_boot = __scsi_add_device(hba->host, 0, 0,
                ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL);
-       if (IS_ERR(hba->sdev_boot)) {
-               ret = PTR_ERR(hba->sdev_boot);
-               hba->sdev_boot = NULL;
+       if (IS_ERR(sdev_boot)) {
+               ret = PTR_ERR(sdev_boot);
                goto remove_sdev_ufs_device;
        }
+       scsi_device_put(sdev_boot);
 
-       hba->sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
+       sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
                ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN), NULL);
-       if (IS_ERR(hba->sdev_rpmb)) {
-               ret = PTR_ERR(hba->sdev_rpmb);
-               hba->sdev_rpmb = NULL;
+       if (IS_ERR(sdev_rpmb)) {
+               ret = PTR_ERR(sdev_rpmb);
                goto remove_sdev_boot;
        }
+       scsi_device_put(sdev_rpmb);
        goto out;
 
 remove_sdev_boot:
-       scsi_remove_device(hba->sdev_boot);
+       scsi_remove_device(sdev_boot);
 remove_sdev_ufs_device:
        scsi_remove_device(hba->sdev_ufs_device);
 out:
        return ret;
 }
 
-/**
- * ufshcd_scsi_remove_wlus - Removes the W-LUs which were added by
- *                          ufshcd_scsi_add_wlus()
- * @hba: per-adapter instance
- *
- */
-static void ufshcd_scsi_remove_wlus(struct ufs_hba *hba)
-{
-       if (hba->sdev_ufs_device) {
-               scsi_remove_device(hba->sdev_ufs_device);
-               hba->sdev_ufs_device = NULL;
-       }
-
-       if (hba->sdev_boot) {
-               scsi_remove_device(hba->sdev_boot);
-               hba->sdev_boot = NULL;
-       }
-
-       if (hba->sdev_rpmb) {
-               scsi_remove_device(hba->sdev_rpmb);
-               hba->sdev_rpmb = NULL;
-       }
-}
-
 /**
  * ufshcd_probe_hba - probe hba to detect device and initialize
  * @hba: per-adapter instance
@@ -4134,6 +4136,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
        if (ret)
                goto out;
 
+       ufshcd_init_pwr_info(hba);
+
        /* UniPro link is active now */
        ufshcd_set_link_active(hba);
 
@@ -4264,12 +4268,18 @@ static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg,
 static inline int ufshcd_config_vreg_lpm(struct ufs_hba *hba,
                                         struct ufs_vreg *vreg)
 {
+       if (!vreg)
+               return 0;
+
        return ufshcd_config_vreg_load(hba->dev, vreg, UFS_VREG_LPM_LOAD_UA);
 }
 
 static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba,
                                         struct ufs_vreg *vreg)
 {
+       if (!vreg)
+               return 0;
+
        return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA);
 }
 
@@ -4471,7 +4481,7 @@ out:
                        if (!IS_ERR_OR_NULL(clki->clk) && clki->enabled)
                                clk_disable_unprepare(clki->clk);
                }
-       } else if (!ret && on) {
+       } else if (on) {
                spin_lock_irqsave(hba->host->host_lock, flags);
                hba->clk_gating.state = CLKS_ON;
                spin_unlock_irqrestore(hba->host->host_lock, flags);
@@ -4675,11 +4685,25 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
 {
        unsigned char cmd[6] = { START_STOP };
        struct scsi_sense_hdr sshdr;
-       struct scsi_device *sdp = hba->sdev_ufs_device;
+       struct scsi_device *sdp;
+       unsigned long flags;
        int ret;
 
-       if (!sdp || !scsi_device_online(sdp))
-               return -ENODEV;
+       spin_lock_irqsave(hba->host->host_lock, flags);
+       sdp = hba->sdev_ufs_device;
+       if (sdp) {
+               ret = scsi_device_get(sdp);
+               if (!ret && !scsi_device_online(sdp)) {
+                       ret = -ENODEV;
+                       scsi_device_put(sdp);
+               }
+       } else {
+               ret = -ENODEV;
+       }
+       spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+       if (ret)
+               return ret;
 
        /*
         * If scsi commands fail, the scsi mid-layer schedules scsi error-
@@ -4718,6 +4742,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
        if (!ret)
                hba->curr_dev_pwr_mode = pwr_mode;
 out:
+       scsi_device_put(sdp);
        hba->host->eh_noresume = 0;
        return ret;
 }
@@ -5087,7 +5112,7 @@ int ufshcd_system_suspend(struct ufs_hba *hba)
        int ret = 0;
 
        if (!hba || !hba->is_powered)
-               goto out;
+               return 0;
 
        if (pm_runtime_suspended(hba->dev)) {
                if (hba->rpm_lvl == hba->spm_lvl)
@@ -5231,7 +5256,6 @@ EXPORT_SYMBOL(ufshcd_shutdown);
 void ufshcd_remove(struct ufs_hba *hba)
 {
        scsi_remove_host(hba->host);
-       ufshcd_scsi_remove_wlus(hba);
        /* disable interrupts */
        ufshcd_disable_intr(hba, hba->intr_mask);
        ufshcd_hba_stop(hba);
index 58ecdff5065c27d2dc3b6c563f641675799435dc..4a574aa458557a14ecc15b0d96d69dc8fa1fc9d8 100644 (file)
@@ -392,8 +392,6 @@ struct ufs_hba {
         * "UFS device" W-LU.
         */
        struct scsi_device *sdev_ufs_device;
-       struct scsi_device *sdev_rpmb;
-       struct scsi_device *sdev_boot;
 
        enum ufs_dev_pwr_mode curr_dev_pwr_mode;
        enum uic_link_state uic_link_state;
index 11a5043959dc9c10126f2a0708a1677092a7ddf8..011a3363c265322631a4021b15c05938ce51c62b 100644 (file)
@@ -31,6 +31,7 @@
 static u32 (*fuse_readl)(const unsigned int offset);
 static int fuse_size;
 struct tegra_sku_info tegra_sku_info;
+EXPORT_SYMBOL(tegra_sku_info);
 
 static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
        [TEGRA_REVISION_UNKNOWN] = "unknown",
index 72e12bad14b9c478a8025db3ef7d31601c083aa4..d0d5542efc06db7a74b46a6a7230a4ce65ba53d5 100644 (file)
@@ -376,9 +376,6 @@ static void pump_transfers(unsigned long data)
        chip = dws->cur_chip;
        spi = message->spi;
 
-       if (unlikely(!chip->clk_div))
-               chip->clk_div = dws->max_freq / chip->speed_hz;
-
        if (message->state == ERROR_STATE) {
                message->status = -EIO;
                goto early_exit;
@@ -419,7 +416,7 @@ static void pump_transfers(unsigned long data)
        if (transfer->speed_hz) {
                speed = chip->speed_hz;
 
-               if (transfer->speed_hz != speed) {
+               if ((transfer->speed_hz != speed) || (!chip->clk_div)) {
                        speed = transfer->speed_hz;
 
                        /* clk_div doesn't support odd number */
@@ -581,7 +578,6 @@ static int dw_spi_setup(struct spi_device *spi)
                dev_err(&spi->dev, "No max speed HZ parameter\n");
                return -EINVAL;
        }
-       chip->speed_hz = spi->max_speed_hz;
 
        chip->tmode = 0; /* Tx & Rx */
        /* Default SPI mode is SCPOL = 0, SCPH = 0 */
index 39e2c0a55a2865acc6c50354cf90fa27263bc922..f63de781c72959c7c29b8fb2bb215f4e33b28f87 100644 (file)
@@ -562,9 +562,9 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
 
        sspi->word_width = DIV_ROUND_UP(bits_per_word, 8);
        txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
-                                          sspi->word_width;
+                                          (sspi->word_width >> 1);
        rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
-                                          sspi->word_width;
+                                          (sspi->word_width >> 1);
 
        if (!(spi->mode & SPI_CS_HIGH))
                regval |= SIRFSOC_SPI_CS_IDLE_STAT;
index ebcb33df2eb22facb58cebc10277c3ab12925a42..50f20f243981e68b0d007ff714476d0a29a42a80 100644 (file)
@@ -615,13 +615,13 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
                                sg_free_table(sgt);
                                return -ENOMEM;
                        }
-                       sg_buf = page_address(vm_page) +
-                               ((size_t)buf & ~PAGE_MASK);
+                       sg_set_page(&sgt->sgl[i], vm_page,
+                                   min, offset_in_page(buf));
                } else {
                        sg_buf = buf;
+                       sg_set_buf(&sgt->sgl[i], sg_buf, min);
                }
 
-               sg_set_buf(&sgt->sgl[i], sg_buf, min);
 
                buf += min;
                len -= min;
index 4690ae9a267f337aff033246b1bad339d7330a82..9425728b7eb5d2c5adf423bc42618d1dcc66127b 100644 (file)
@@ -86,8 +86,6 @@ source "drivers/staging/gdm72xx/Kconfig"
 
 source "drivers/staging/gdm724x/Kconfig"
 
-source "drivers/staging/imx-drm/Kconfig"
-
 source "drivers/staging/fwserial/Kconfig"
 
 source "drivers/staging/goldfish/Kconfig"
index c780a0e70e151ce0ce55929df910e0c01b3bc97c..bc233dd98a95f99acf7f6d865c45598c3848bed1 100644 (file)
@@ -36,7 +36,6 @@ obj-$(CONFIG_STAGING_BOARD)   += board/
 obj-$(CONFIG_USB_WPAN_HCD)     += ozwpan/
 obj-$(CONFIG_WIMAX_GDM72XX)    += gdm72xx/
 obj-$(CONFIG_LTE_GDM724X)      += gdm724x/
-obj-$(CONFIG_DRM_IMX)          += imx-drm/
 obj-$(CONFIG_FIREWIRE_SERIAL)  += fwserial/
 obj-$(CONFIG_GOLDFISH)         += goldfish/
 obj-$(CONFIG_LUSTRE_FS)                += lustre/
diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
deleted file mode 100644 (file)
index 82fb758..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-config DRM_IMX
-       tristate "DRM Support for Freescale i.MX"
-       select DRM_KMS_HELPER
-       select DRM_KMS_FB_HELPER
-       select VIDEOMODE_HELPERS
-       select DRM_GEM_CMA_HELPER
-       select DRM_KMS_CMA_HELPER
-       depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM)
-       help
-         enable i.MX graphics support
-
-config DRM_IMX_FB_HELPER
-       tristate "provide legacy framebuffer /dev/fb0"
-       select DRM_KMS_CMA_HELPER
-       depends on DRM_IMX
-       help
-         The DRM framework can provide a legacy /dev/fb0 framebuffer
-         for your device. This is necessary to get a framebuffer console
-         and also for applications using the legacy framebuffer API
-
-config DRM_IMX_PARALLEL_DISPLAY
-       tristate "Support for parallel displays"
-       select DRM_PANEL
-       depends on DRM_IMX
-       select VIDEOMODE_HELPERS
-
-config DRM_IMX_TVE
-       tristate "Support for TV and VGA displays"
-       depends on DRM_IMX
-       select REGMAP_MMIO
-       help
-         Choose this to enable the internal Television Encoder (TVe)
-         found on i.MX53 processors.
-
-config DRM_IMX_LDB
-       tristate "Support for LVDS displays"
-       depends on DRM_IMX && MFD_SYSCON
-       help
-         Choose this to enable the internal LVDS Display Bridge (LDB)
-         found on i.MX53 and i.MX6 processors.
-
-config DRM_IMX_IPUV3
-       tristate "DRM Support for i.MX IPUv3"
-       depends on DRM_IMX
-       depends on IMX_IPUV3_CORE
-       help
-         Choose this if you have a i.MX5 or i.MX6 processor.
-
-config DRM_IMX_HDMI
-       tristate "Freescale i.MX DRM HDMI"
-       depends on DRM_IMX
-       help
-         Choose this if you want to use HDMI on i.MX6.
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
deleted file mode 100644 (file)
index 582c438..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-
-imxdrm-objs := imx-drm-core.o
-
-obj-$(CONFIG_DRM_IMX) += imxdrm.o
-
-obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
-obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
-obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
-
-imx-ipuv3-crtc-objs  := ipuv3-crtc.o ipuv3-plane.o
-obj-$(CONFIG_DRM_IMX_IPUV3)    += imx-ipuv3-crtc.o
-obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o
diff --git a/drivers/staging/imx-drm/TODO b/drivers/staging/imx-drm/TODO
deleted file mode 100644 (file)
index 29636fb..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-TODO:
-- get DRM Maintainer review for this code
-- decide where to put the base driver. It is not specific to a subsystem
-  and would be used by DRM/KMS and media/V4L2
-
-Missing features (not necessarily for moving out of staging):
-
-- Add support for IC (Image converter)
-- Add support for CSI (CMOS Sensor interface)
-- Add support for VDIC (Video Deinterlacer)
-
-Many work-in-progress patches for the above features exist. Contact
-Sascha Hauer <kernel@pengutronix.de> if you are interested in working
-on a specific feature.
-
-Please send any patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org> and
-Sascha Hauer <kernel@pengutronix.de>
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
deleted file mode 100644 (file)
index 2f80072..0000000
+++ /dev/null
@@ -1,705 +0,0 @@
-/*
- * Freescale i.MX drm driver
- *
- * Copyright (C) 2011 Sascha Hauer, Pengutronix
- *
- * 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/component.h>
-#include <linux/device.h>
-#include <linux/fb.h>
-#include <linux/module.h>
-#include <linux/of_graph.h>
-#include <linux/platform_device.h>
-#include <drm/drmP.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-#include <drm/drm_plane_helper.h>
-
-#include "imx-drm.h"
-
-#define MAX_CRTC       4
-
-struct imx_drm_crtc;
-
-struct imx_drm_component {
-       struct device_node *of_node;
-       struct list_head list;
-};
-
-struct imx_drm_device {
-       struct drm_device                       *drm;
-       struct imx_drm_crtc                     *crtc[MAX_CRTC];
-       int                                     pipes;
-       struct drm_fbdev_cma                    *fbhelper;
-};
-
-struct imx_drm_crtc {
-       struct drm_crtc                         *crtc;
-       int                                     pipe;
-       struct imx_drm_crtc_helper_funcs        imx_drm_helper_funcs;
-       struct device_node                      *port;
-};
-
-static int legacyfb_depth = 16;
-module_param(legacyfb_depth, int, 0444);
-
-int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
-{
-       return crtc->pipe;
-}
-EXPORT_SYMBOL_GPL(imx_drm_crtc_id);
-
-static void imx_drm_driver_lastclose(struct drm_device *drm)
-{
-#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
-       struct imx_drm_device *imxdrm = drm->dev_private;
-
-       if (imxdrm->fbhelper)
-               drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
-#endif
-}
-
-static int imx_drm_driver_unload(struct drm_device *drm)
-{
-#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
-       struct imx_drm_device *imxdrm = drm->dev_private;
-#endif
-
-       drm_kms_helper_poll_fini(drm);
-
-#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
-       if (imxdrm->fbhelper)
-               drm_fbdev_cma_fini(imxdrm->fbhelper);
-#endif
-
-       component_unbind_all(drm->dev, drm);
-
-       drm_vblank_cleanup(drm);
-       drm_mode_config_cleanup(drm);
-
-       platform_set_drvdata(drm->platformdev, NULL);
-
-       return 0;
-}
-
-static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
-{
-       struct imx_drm_device *imxdrm = crtc->dev->dev_private;
-       unsigned i;
-
-       for (i = 0; i < MAX_CRTC; i++)
-               if (imxdrm->crtc[i] && imxdrm->crtc[i]->crtc == crtc)
-                       return imxdrm->crtc[i];
-
-       return NULL;
-}
-
-int imx_drm_panel_format_pins(struct drm_encoder *encoder,
-               u32 interface_pix_fmt, int hsync_pin, int vsync_pin)
-{
-       struct imx_drm_crtc_helper_funcs *helper;
-       struct imx_drm_crtc *imx_crtc;
-
-       imx_crtc = imx_drm_find_crtc(encoder->crtc);
-       if (!imx_crtc)
-               return -EINVAL;
-
-       helper = &imx_crtc->imx_drm_helper_funcs;
-       if (helper->set_interface_pix_fmt)
-               return helper->set_interface_pix_fmt(encoder->crtc,
-                               encoder->encoder_type, interface_pix_fmt,
-                               hsync_pin, vsync_pin);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins);
-
-int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt)
-{
-       return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3);
-}
-EXPORT_SYMBOL_GPL(imx_drm_panel_format);
-
-int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
-{
-       return drm_vblank_get(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
-}
-EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
-
-void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
-{
-       drm_vblank_put(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
-}
-EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
-
-void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
-{
-       drm_handle_vblank(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
-}
-EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
-
-static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
-{
-       struct imx_drm_device *imxdrm = drm->dev_private;
-       struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
-       int ret;
-
-       if (!imx_drm_crtc)
-               return -EINVAL;
-
-       if (!imx_drm_crtc->imx_drm_helper_funcs.enable_vblank)
-               return -ENOSYS;
-
-       ret = imx_drm_crtc->imx_drm_helper_funcs.enable_vblank(
-                       imx_drm_crtc->crtc);
-
-       return ret;
-}
-
-static void imx_drm_disable_vblank(struct drm_device *drm, int crtc)
-{
-       struct imx_drm_device *imxdrm = drm->dev_private;
-       struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
-
-       if (!imx_drm_crtc)
-               return;
-
-       if (!imx_drm_crtc->imx_drm_helper_funcs.disable_vblank)
-               return;
-
-       imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(imx_drm_crtc->crtc);
-}
-
-static void imx_drm_driver_preclose(struct drm_device *drm,
-               struct drm_file *file)
-{
-       int i;
-
-       if (!file->is_master)
-               return;
-
-       for (i = 0; i < MAX_CRTC; i++)
-               imx_drm_disable_vblank(drm, i);
-}
-
-static const struct file_operations imx_drm_driver_fops = {
-       .owner = THIS_MODULE,
-       .open = drm_open,
-       .release = drm_release,
-       .unlocked_ioctl = drm_ioctl,
-       .mmap = drm_gem_cma_mmap,
-       .poll = drm_poll,
-       .read = drm_read,
-       .llseek = noop_llseek,
-};
-
-void imx_drm_connector_destroy(struct drm_connector *connector)
-{
-       drm_connector_unregister(connector);
-       drm_connector_cleanup(connector);
-}
-EXPORT_SYMBOL_GPL(imx_drm_connector_destroy);
-
-void imx_drm_encoder_destroy(struct drm_encoder *encoder)
-{
-       drm_encoder_cleanup(encoder);
-}
-EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
-
-static void imx_drm_output_poll_changed(struct drm_device *drm)
-{
-#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
-       struct imx_drm_device *imxdrm = drm->dev_private;
-
-       drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
-#endif
-}
-
-static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
-       .fb_create = drm_fb_cma_create,
-       .output_poll_changed = imx_drm_output_poll_changed,
-};
-
-/*
- * Main DRM initialisation. This binds, initialises and registers
- * with DRM the subcomponents of the driver.
- */
-static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
-{
-       struct imx_drm_device *imxdrm;
-       struct drm_connector *connector;
-       int ret;
-
-       imxdrm = devm_kzalloc(drm->dev, sizeof(*imxdrm), GFP_KERNEL);
-       if (!imxdrm)
-               return -ENOMEM;
-
-       imxdrm->drm = drm;
-
-       drm->dev_private = imxdrm;
-
-       /*
-        * enable drm irq mode.
-        * - with irq_enabled = true, we can use the vblank feature.
-        *
-        * P.S. note that we wouldn't use drm irq handler but
-        *      just specific driver own one instead because
-        *      drm framework supports only one irq handler and
-        *      drivers can well take care of their interrupts
-        */
-       drm->irq_enabled = true;
-
-       /*
-        * set max width and height as default value(4096x4096).
-        * this value would be used to check framebuffer size limitation
-        * at drm_mode_addfb().
-        */
-       drm->mode_config.min_width = 64;
-       drm->mode_config.min_height = 64;
-       drm->mode_config.max_width = 4096;
-       drm->mode_config.max_height = 4096;
-       drm->mode_config.funcs = &imx_drm_mode_config_funcs;
-
-       drm_mode_config_init(drm);
-
-       ret = drm_vblank_init(drm, MAX_CRTC);
-       if (ret)
-               goto err_kms;
-
-       /*
-        * with vblank_disable_allowed = true, vblank interrupt will be
-        * disabled by drm timer once a current process gives up ownership
-        * of vblank event. (after drm_vblank_put function is called)
-        */
-       drm->vblank_disable_allowed = true;
-
-       platform_set_drvdata(drm->platformdev, drm);
-
-       /* Now try and bind all our sub-components */
-       ret = component_bind_all(drm->dev, drm);
-       if (ret)
-               goto err_vblank;
-
-       /*
-        * All components are now added, we can publish the connector sysfs
-        * entries to userspace.  This will generate hotplug events and so
-        * userspace will expect to be able to access DRM at this point.
-        */
-       list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
-               ret = drm_connector_register(connector);
-               if (ret) {
-                       dev_err(drm->dev,
-                               "[CONNECTOR:%d:%s] drm_connector_register failed: %d\n",
-                               connector->base.id,
-                               connector->name, ret);
-                       goto err_unbind;
-               }
-       }
-
-       /*
-        * All components are now initialised, so setup the fb helper.
-        * The fb helper takes copies of key hardware information, so the
-        * crtcs/connectors/encoders must not change after this point.
-        */
-#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
-       if (legacyfb_depth != 16 && legacyfb_depth != 32) {
-               dev_warn(drm->dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
-               legacyfb_depth = 16;
-       }
-       imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
-                               drm->mode_config.num_crtc, MAX_CRTC);
-       if (IS_ERR(imxdrm->fbhelper)) {
-               ret = PTR_ERR(imxdrm->fbhelper);
-               imxdrm->fbhelper = NULL;
-               goto err_unbind;
-       }
-#endif
-
-       drm_kms_helper_poll_init(drm);
-
-       return 0;
-
-err_unbind:
-       component_unbind_all(drm->dev, drm);
-err_vblank:
-       drm_vblank_cleanup(drm);
-err_kms:
-       drm_mode_config_cleanup(drm);
-
-       return ret;
-}
-
-/*
- * imx_drm_add_crtc - add a new crtc
- */
-int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
-               struct imx_drm_crtc **new_crtc,
-               const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
-               struct device_node *port)
-{
-       struct imx_drm_device *imxdrm = drm->dev_private;
-       struct imx_drm_crtc *imx_drm_crtc;
-       int ret;
-
-       /*
-        * The vblank arrays are dimensioned by MAX_CRTC - we can't
-        * pass IDs greater than this to those functions.
-        */
-       if (imxdrm->pipes >= MAX_CRTC)
-               return -EINVAL;
-
-       if (imxdrm->drm->open_count)
-               return -EBUSY;
-
-       imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL);
-       if (!imx_drm_crtc)
-               return -ENOMEM;
-
-       imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
-       imx_drm_crtc->pipe = imxdrm->pipes++;
-       imx_drm_crtc->port = port;
-       imx_drm_crtc->crtc = crtc;
-
-       imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
-
-       *new_crtc = imx_drm_crtc;
-
-       ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
-       if (ret)
-               goto err_register;
-
-       drm_crtc_helper_add(crtc,
-                       imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
-
-       drm_crtc_init(drm, crtc,
-                       imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
-
-       return 0;
-
-err_register:
-       imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
-       kfree(imx_drm_crtc);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
-
-/*
- * imx_drm_remove_crtc - remove a crtc
- */
-int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
-{
-       struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private;
-
-       drm_crtc_cleanup(imx_drm_crtc->crtc);
-
-       imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
-
-       kfree(imx_drm_crtc);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
-
-/*
- * Find the DRM CRTC possible mask for the connected endpoint.
- *
- * The encoder possible masks are defined by their position in the
- * mode_config crtc_list.  This means that CRTCs must not be added
- * or removed once the DRM device has been fully initialised.
- */
-static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
-       struct device_node *endpoint)
-{
-       struct device_node *port;
-       unsigned i;
-
-       port = of_graph_get_remote_port(endpoint);
-       if (!port)
-               return 0;
-       of_node_put(port);
-
-       for (i = 0; i < MAX_CRTC; i++) {
-               struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
-
-               if (imx_drm_crtc && imx_drm_crtc->port == port)
-                       return drm_crtc_mask(imx_drm_crtc->crtc);
-       }
-
-       return 0;
-}
-
-static struct device_node *imx_drm_of_get_next_endpoint(
-               const struct device_node *parent, struct device_node *prev)
-{
-       struct device_node *node = of_graph_get_next_endpoint(parent, prev);
-
-       of_node_put(prev);
-       return node;
-}
-
-int imx_drm_encoder_parse_of(struct drm_device *drm,
-       struct drm_encoder *encoder, struct device_node *np)
-{
-       struct imx_drm_device *imxdrm = drm->dev_private;
-       struct device_node *ep = NULL;
-       uint32_t crtc_mask = 0;
-       int i;
-
-       for (i = 0; ; i++) {
-               u32 mask;
-
-               ep = imx_drm_of_get_next_endpoint(np, ep);
-               if (!ep)
-                       break;
-
-               mask = imx_drm_find_crtc_mask(imxdrm, ep);
-
-               /*
-                * If we failed to find the CRTC(s) which this encoder is
-                * supposed to be connected to, it's because the CRTC has
-                * not been registered yet.  Defer probing, and hope that
-                * the required CRTC is added later.
-                */
-               if (mask == 0)
-                       return -EPROBE_DEFER;
-
-               crtc_mask |= mask;
-       }
-
-       of_node_put(ep);
-       if (i == 0)
-               return -ENOENT;
-
-       encoder->possible_crtcs = crtc_mask;
-
-       /* FIXME: this is the mask of outputs which can clone this output. */
-       encoder->possible_clones = ~0;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
-
-/*
- * @node: device tree node containing encoder input ports
- * @encoder: drm_encoder
- */
-int imx_drm_encoder_get_mux_id(struct device_node *node,
-                              struct drm_encoder *encoder)
-{
-       struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
-       struct device_node *ep = NULL;
-       struct of_endpoint endpoint;
-       struct device_node *port;
-       int ret;
-
-       if (!node || !imx_crtc)
-               return -EINVAL;
-
-       do {
-               ep = imx_drm_of_get_next_endpoint(node, ep);
-               if (!ep)
-                       break;
-
-               port = of_graph_get_remote_port(ep);
-               of_node_put(port);
-               if (port == imx_crtc->port) {
-                       ret = of_graph_parse_endpoint(ep, &endpoint);
-                       return ret ? ret : endpoint.port;
-               }
-       } while (ep);
-
-       return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
-
-static const struct drm_ioctl_desc imx_drm_ioctls[] = {
-       /* none so far */
-};
-
-static struct drm_driver imx_drm_driver = {
-       .driver_features        = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
-       .load                   = imx_drm_driver_load,
-       .unload                 = imx_drm_driver_unload,
-       .lastclose              = imx_drm_driver_lastclose,
-       .preclose               = imx_drm_driver_preclose,
-       .set_busid              = drm_platform_set_busid,
-       .gem_free_object        = drm_gem_cma_free_object,
-       .gem_vm_ops             = &drm_gem_cma_vm_ops,
-       .dumb_create            = drm_gem_cma_dumb_create,
-       .dumb_map_offset        = drm_gem_cma_dumb_map_offset,
-       .dumb_destroy           = drm_gem_dumb_destroy,
-
-       .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
-       .prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
-       .gem_prime_import       = drm_gem_prime_import,
-       .gem_prime_export       = drm_gem_prime_export,
-       .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
-       .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
-       .gem_prime_vmap         = drm_gem_cma_prime_vmap,
-       .gem_prime_vunmap       = drm_gem_cma_prime_vunmap,
-       .gem_prime_mmap         = drm_gem_cma_prime_mmap,
-       .get_vblank_counter     = drm_vblank_count,
-       .enable_vblank          = imx_drm_enable_vblank,
-       .disable_vblank         = imx_drm_disable_vblank,
-       .ioctls                 = imx_drm_ioctls,
-       .num_ioctls             = ARRAY_SIZE(imx_drm_ioctls),
-       .fops                   = &imx_drm_driver_fops,
-       .name                   = "imx-drm",
-       .desc                   = "i.MX DRM graphics",
-       .date                   = "20120507",
-       .major                  = 1,
-       .minor                  = 0,
-       .patchlevel             = 0,
-};
-
-static int compare_of(struct device *dev, void *data)
-{
-       struct device_node *np = data;
-
-       /* Special case for LDB, one device for two channels */
-       if (of_node_cmp(np->name, "lvds-channel") == 0) {
-               np = of_get_parent(np);
-               of_node_put(np);
-       }
-
-       return dev->of_node == np;
-}
-
-static int imx_drm_bind(struct device *dev)
-{
-       return drm_platform_init(&imx_drm_driver, to_platform_device(dev));
-}
-
-static void imx_drm_unbind(struct device *dev)
-{
-       drm_put_dev(dev_get_drvdata(dev));
-}
-
-static const struct component_master_ops imx_drm_ops = {
-       .bind = imx_drm_bind,
-       .unbind = imx_drm_unbind,
-};
-
-static int imx_drm_platform_probe(struct platform_device *pdev)
-{
-       struct device_node *ep, *port, *remote;
-       struct component_match *match = NULL;
-       int ret;
-       int i;
-
-       /*
-        * Bind the IPU display interface ports first, so that
-        * imx_drm_encoder_parse_of called from encoder .bind callbacks
-        * works as expected.
-        */
-       for (i = 0; ; i++) {
-               port = of_parse_phandle(pdev->dev.of_node, "ports", i);
-               if (!port)
-                       break;
-
-               component_match_add(&pdev->dev, &match, compare_of, port);
-       }
-
-       if (i == 0) {
-               dev_err(&pdev->dev, "missing 'ports' property\n");
-               return -ENODEV;
-       }
-
-       /* Then bind all encoders */
-       for (i = 0; ; i++) {
-               port = of_parse_phandle(pdev->dev.of_node, "ports", i);
-               if (!port)
-                       break;
-
-               for_each_child_of_node(port, ep) {
-                       remote = of_graph_get_remote_port_parent(ep);
-                       if (!remote || !of_device_is_available(remote)) {
-                               of_node_put(remote);
-                               continue;
-                       } else if (!of_device_is_available(remote->parent)) {
-                               dev_warn(&pdev->dev, "parent device of %s is not available\n",
-                                        remote->full_name);
-                               of_node_put(remote);
-                               continue;
-                       }
-
-                       component_match_add(&pdev->dev, &match, compare_of, remote);
-                       of_node_put(remote);
-               }
-               of_node_put(port);
-       }
-
-       ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
-       if (ret)
-               return ret;
-
-       return component_master_add_with_match(&pdev->dev, &imx_drm_ops, match);
-}
-
-static int imx_drm_platform_remove(struct platform_device *pdev)
-{
-       component_master_del(&pdev->dev, &imx_drm_ops);
-       return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int imx_drm_suspend(struct device *dev)
-{
-       struct drm_device *drm_dev = dev_get_drvdata(dev);
-
-       /* The drm_dev is NULL before .load hook is called */
-       if (drm_dev == NULL)
-               return 0;
-
-       drm_kms_helper_poll_disable(drm_dev);
-
-       return 0;
-}
-
-static int imx_drm_resume(struct device *dev)
-{
-       struct drm_device *drm_dev = dev_get_drvdata(dev);
-
-       if (drm_dev == NULL)
-               return 0;
-
-       drm_helper_resume_force_mode(drm_dev);
-       drm_kms_helper_poll_enable(drm_dev);
-
-       return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(imx_drm_pm_ops, imx_drm_suspend, imx_drm_resume);
-
-static const struct of_device_id imx_drm_dt_ids[] = {
-       { .compatible = "fsl,imx-display-subsystem", },
-       { /* sentinel */ },
-};
-MODULE_DEVICE_TABLE(of, imx_drm_dt_ids);
-
-static struct platform_driver imx_drm_pdrv = {
-       .probe          = imx_drm_platform_probe,
-       .remove         = imx_drm_platform_remove,
-       .driver         = {
-               .owner  = THIS_MODULE,
-               .name   = "imx-drm",
-               .pm     = &imx_drm_pm_ops,
-               .of_match_table = imx_drm_dt_ids,
-       },
-};
-module_platform_driver(imx_drm_pdrv);
-
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-MODULE_DESCRIPTION("i.MX drm driver core");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
deleted file mode 100644 (file)
index 7453ae0..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef _IMX_DRM_H_
-#define _IMX_DRM_H_
-
-struct device_node;
-struct drm_crtc;
-struct drm_connector;
-struct drm_device;
-struct drm_display_mode;
-struct drm_encoder;
-struct drm_fbdev_cma;
-struct drm_framebuffer;
-struct imx_drm_crtc;
-struct platform_device;
-
-int imx_drm_crtc_id(struct imx_drm_crtc *crtc);
-
-struct imx_drm_crtc_helper_funcs {
-       int (*enable_vblank)(struct drm_crtc *crtc);
-       void (*disable_vblank)(struct drm_crtc *crtc);
-       int (*set_interface_pix_fmt)(struct drm_crtc *crtc, u32 encoder_type,
-                       u32 pix_fmt, int hsync_pin, int vsync_pin);
-       const struct drm_crtc_helper_funcs *crtc_helper_funcs;
-       const struct drm_crtc_funcs *crtc_funcs;
-};
-
-int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
-               struct imx_drm_crtc **new_crtc,
-               const struct imx_drm_crtc_helper_funcs *imx_helper_funcs,
-               struct device_node *port);
-int imx_drm_remove_crtc(struct imx_drm_crtc *);
-int imx_drm_init_drm(struct platform_device *pdev,
-               int preferred_bpp);
-int imx_drm_exit_drm(void);
-
-int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc);
-void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc);
-void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc);
-
-void imx_drm_mode_config_init(struct drm_device *drm);
-
-struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
-
-int imx_drm_panel_format_pins(struct drm_encoder *encoder,
-               u32 interface_pix_fmt, int hsync_pin, int vsync_pin);
-int imx_drm_panel_format(struct drm_encoder *encoder,
-               u32 interface_pix_fmt);
-
-int imx_drm_encoder_get_mux_id(struct device_node *node,
-               struct drm_encoder *encoder);
-int imx_drm_encoder_parse_of(struct drm_device *drm,
-       struct drm_encoder *encoder, struct device_node *np);
-
-void imx_drm_connector_destroy(struct drm_connector *connector);
-void imx_drm_encoder_destroy(struct drm_encoder *encoder);
-
-#endif /* _IMX_DRM_H_ */
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
deleted file mode 100644 (file)
index aaec6b2..0000000
+++ /dev/null
@@ -1,1767 +0,0 @@
-/*
- * Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
- *
- * 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.
- *
- * SH-Mobile High-Definition Multimedia Interface (HDMI) driver
- * for SLISHDMI13T and SLIPHDMIT IP cores
- *
- * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- */
-
-#include <linux/component.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/hdmi.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
-#include <linux/of_device.h>
-
-#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_edid.h>
-#include <drm/drm_encoder_slave.h>
-#include <video/imx-ipu-v3.h>
-
-#include "imx-hdmi.h"
-#include "imx-drm.h"
-
-#define HDMI_EDID_LEN          512
-
-#define RGB                    0
-#define YCBCR444               1
-#define YCBCR422_16BITS                2
-#define YCBCR422_8BITS         3
-#define XVYCC444               4
-
-enum hdmi_datamap {
-       RGB444_8B = 0x01,
-       RGB444_10B = 0x03,
-       RGB444_12B = 0x05,
-       RGB444_16B = 0x07,
-       YCbCr444_8B = 0x09,
-       YCbCr444_10B = 0x0B,
-       YCbCr444_12B = 0x0D,
-       YCbCr444_16B = 0x0F,
-       YCbCr422_8B = 0x16,
-       YCbCr422_10B = 0x14,
-       YCbCr422_12B = 0x12,
-};
-
-enum imx_hdmi_devtype {
-       IMX6Q_HDMI,
-       IMX6DL_HDMI,
-};
-
-static const u16 csc_coeff_default[3][4] = {
-       { 0x2000, 0x0000, 0x0000, 0x0000 },
-       { 0x0000, 0x2000, 0x0000, 0x0000 },
-       { 0x0000, 0x0000, 0x2000, 0x0000 }
-};
-
-static const u16 csc_coeff_rgb_out_eitu601[3][4] = {
-       { 0x2000, 0x6926, 0x74fd, 0x010e },
-       { 0x2000, 0x2cdd, 0x0000, 0x7e9a },
-       { 0x2000, 0x0000, 0x38b4, 0x7e3b }
-};
-
-static const u16 csc_coeff_rgb_out_eitu709[3][4] = {
-       { 0x2000, 0x7106, 0x7a02, 0x00a7 },
-       { 0x2000, 0x3264, 0x0000, 0x7e6d },
-       { 0x2000, 0x0000, 0x3b61, 0x7e25 }
-};
-
-static const u16 csc_coeff_rgb_in_eitu601[3][4] = {
-       { 0x2591, 0x1322, 0x074b, 0x0000 },
-       { 0x6535, 0x2000, 0x7acc, 0x0200 },
-       { 0x6acd, 0x7534, 0x2000, 0x0200 }
-};
-
-static const u16 csc_coeff_rgb_in_eitu709[3][4] = {
-       { 0x2dc5, 0x0d9b, 0x049e, 0x0000 },
-       { 0x62f0, 0x2000, 0x7d11, 0x0200 },
-       { 0x6756, 0x78ab, 0x2000, 0x0200 }
-};
-
-struct hdmi_vmode {
-       bool mdvi;
-       bool mhsyncpolarity;
-       bool mvsyncpolarity;
-       bool minterlaced;
-       bool mdataenablepolarity;
-
-       unsigned int mpixelclock;
-       unsigned int mpixelrepetitioninput;
-       unsigned int mpixelrepetitionoutput;
-};
-
-struct hdmi_data_info {
-       unsigned int enc_in_format;
-       unsigned int enc_out_format;
-       unsigned int enc_color_depth;
-       unsigned int colorimetry;
-       unsigned int pix_repet_factor;
-       unsigned int hdcp_enable;
-       struct hdmi_vmode video_mode;
-};
-
-struct imx_hdmi {
-       struct drm_connector connector;
-       struct drm_encoder encoder;
-
-       enum imx_hdmi_devtype dev_type;
-       struct device *dev;
-       struct clk *isfr_clk;
-       struct clk *iahb_clk;
-
-       struct hdmi_data_info hdmi_data;
-       int vic;
-
-       u8 edid[HDMI_EDID_LEN];
-       bool cable_plugin;
-
-       bool phy_enabled;
-       struct drm_display_mode previous_mode;
-
-       struct regmap *regmap;
-       struct i2c_adapter *ddc;
-       void __iomem *regs;
-
-       unsigned int sample_rate;
-       int ratio;
-};
-
-static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di)
-{
-       regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
-                          IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
-                          ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
-}
-
-static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
-{
-       writeb(val, hdmi->regs + offset);
-}
-
-static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
-{
-       return readb(hdmi->regs + offset);
-}
-
-static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
-{
-       u8 val = hdmi_readb(hdmi, reg) & ~mask;
-
-       val |= data & mask;
-       hdmi_writeb(hdmi, val, reg);
-}
-
-static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
-                     u8 shift, u8 mask)
-{
-       hdmi_modb(hdmi, data << shift, mask, reg);
-}
-
-static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
-                                        unsigned int value)
-{
-       hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
-       hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2);
-       hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);
-
-       /* nshift factor = 0 */
-       hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
-}
-
-static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
-{
-       /* Must be set/cleared first */
-       hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
-
-       hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
-       hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
-       hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
-                   HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
-}
-
-static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk,
-                                  unsigned int ratio)
-{
-       unsigned int n = (128 * freq) / 1000;
-
-       switch (freq) {
-       case 32000:
-               if (pixel_clk == 25170000)
-                       n = (ratio == 150) ? 9152 : 4576;
-               else if (pixel_clk == 27020000)
-                       n = (ratio == 150) ? 8192 : 4096;
-               else if (pixel_clk == 74170000 || pixel_clk == 148350000)
-                       n = 11648;
-               else
-                       n = 4096;
-               break;
-
-       case 44100:
-               if (pixel_clk == 25170000)
-                       n = 7007;
-               else if (pixel_clk == 74170000)
-                       n = 17836;
-               else if (pixel_clk == 148350000)
-                       n = (ratio == 150) ? 17836 : 8918;
-               else
-                       n = 6272;
-               break;
-
-       case 48000:
-               if (pixel_clk == 25170000)
-                       n = (ratio == 150) ? 9152 : 6864;
-               else if (pixel_clk == 27020000)
-                       n = (ratio == 150) ? 8192 : 6144;
-               else if (pixel_clk == 74170000)
-                       n = 11648;
-               else if (pixel_clk == 148350000)
-                       n = (ratio == 150) ? 11648 : 5824;
-               else
-                       n = 6144;
-               break;
-
-       case 88200:
-               n = hdmi_compute_n(44100, pixel_clk, ratio) * 2;
-               break;
-
-       case 96000:
-               n = hdmi_compute_n(48000, pixel_clk, ratio) * 2;
-               break;
-
-       case 176400:
-               n = hdmi_compute_n(44100, pixel_clk, ratio) * 4;
-               break;
-
-       case 192000:
-               n = hdmi_compute_n(48000, pixel_clk, ratio) * 4;
-               break;
-
-       default:
-               break;
-       }
-
-       return n;
-}
-
-static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
-                                    unsigned int ratio)
-{
-       unsigned int cts = 0;
-
-       pr_debug("%s: freq: %d pixel_clk: %ld ratio: %d\n", __func__, freq,
-                pixel_clk, ratio);
-
-       switch (freq) {
-       case 32000:
-               if (pixel_clk == 297000000) {
-                       cts = 222750;
-                       break;
-               }
-       case 48000:
-       case 96000:
-       case 192000:
-               switch (pixel_clk) {
-               case 25200000:
-               case 27000000:
-               case 54000000:
-               case 74250000:
-               case 148500000:
-                       cts = pixel_clk / 1000;
-                       break;
-               case 297000000:
-                       cts = 247500;
-                       break;
-               /*
-                * All other TMDS clocks are not supported by
-                * DWC_hdmi_tx. The TMDS clocks divided or
-                * multiplied by 1,001 coefficients are not
-                * supported.
-                */
-               default:
-                       break;
-               }
-               break;
-       case 44100:
-       case 88200:
-       case 176400:
-               switch (pixel_clk) {
-               case 25200000:
-                       cts = 28000;
-                       break;
-               case 27000000:
-                       cts = 30000;
-                       break;
-               case 54000000:
-                       cts = 60000;
-                       break;
-               case 74250000:
-                       cts = 82500;
-                       break;
-               case 148500000:
-                       cts = 165000;
-                       break;
-               case 297000000:
-                       cts = 247500;
-                       break;
-               default:
-                       break;
-               }
-               break;
-       default:
-               break;
-       }
-       if (ratio == 100)
-               return cts;
-       return (cts * ratio) / 100;
-}
-
-static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
-       unsigned long pixel_clk)
-{
-       unsigned int clk_n, clk_cts;
-
-       clk_n = hdmi_compute_n(hdmi->sample_rate, pixel_clk,
-                              hdmi->ratio);
-       clk_cts = hdmi_compute_cts(hdmi->sample_rate, pixel_clk,
-                                  hdmi->ratio);
-
-       if (!clk_cts) {
-               dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
-                        __func__, pixel_clk);
-               return;
-       }
-
-       dev_dbg(hdmi->dev, "%s: samplerate=%d  ratio=%d  pixelclk=%lu  N=%d cts=%d\n",
-               __func__, hdmi->sample_rate, hdmi->ratio,
-               pixel_clk, clk_n, clk_cts);
-
-       hdmi_set_clock_regenerator_n(hdmi, clk_n);
-       hdmi_regenerate_cts(hdmi, clk_cts);
-}
-
-static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi)
-{
-       hdmi_set_clk_regenerator(hdmi, 74250000);
-}
-
-static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
-{
-       hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
-}
-
-/*
- * this submodule is responsible for the video data synchronization.
- * for example, for RGB 4:4:4 input, the data map is defined as
- *                     pin{47~40} <==> R[7:0]
- *                     pin{31~24} <==> G[7:0]
- *                     pin{15~8}  <==> B[7:0]
- */
-static void hdmi_video_sample(struct imx_hdmi *hdmi)
-{
-       int color_format = 0;
-       u8 val;
-
-       if (hdmi->hdmi_data.enc_in_format == RGB) {
-               if (hdmi->hdmi_data.enc_color_depth == 8)
-                       color_format = 0x01;
-               else if (hdmi->hdmi_data.enc_color_depth == 10)
-                       color_format = 0x03;
-               else if (hdmi->hdmi_data.enc_color_depth == 12)
-                       color_format = 0x05;
-               else if (hdmi->hdmi_data.enc_color_depth == 16)
-                       color_format = 0x07;
-               else
-                       return;
-       } else if (hdmi->hdmi_data.enc_in_format == YCBCR444) {
-               if (hdmi->hdmi_data.enc_color_depth == 8)
-                       color_format = 0x09;
-               else if (hdmi->hdmi_data.enc_color_depth == 10)
-                       color_format = 0x0B;
-               else if (hdmi->hdmi_data.enc_color_depth == 12)
-                       color_format = 0x0D;
-               else if (hdmi->hdmi_data.enc_color_depth == 16)
-                       color_format = 0x0F;
-               else
-                       return;
-       } else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) {
-               if (hdmi->hdmi_data.enc_color_depth == 8)
-                       color_format = 0x16;
-               else if (hdmi->hdmi_data.enc_color_depth == 10)
-                       color_format = 0x14;
-               else if (hdmi->hdmi_data.enc_color_depth == 12)
-                       color_format = 0x12;
-               else
-                       return;
-       }
-
-       val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
-               ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
-               HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
-       hdmi_writeb(hdmi, val, HDMI_TX_INVID0);
-
-       /* Enable TX stuffing: When DE is inactive, fix the output data to 0 */
-       val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
-               HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
-               HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
-       hdmi_writeb(hdmi, val, HDMI_TX_INSTUFFING);
-       hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA0);
-       hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA1);
-       hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA0);
-       hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA1);
-       hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA0);
-       hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1);
-}
-
-static int is_color_space_conversion(struct imx_hdmi *hdmi)
-{
-       return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format;
-}
-
-static int is_color_space_decimation(struct imx_hdmi *hdmi)
-{
-       if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
-               return 0;
-       if (hdmi->hdmi_data.enc_in_format == RGB ||
-           hdmi->hdmi_data.enc_in_format == YCBCR444)
-               return 1;
-       return 0;
-}
-
-static int is_color_space_interpolation(struct imx_hdmi *hdmi)
-{
-       if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
-               return 0;
-       if (hdmi->hdmi_data.enc_out_format == RGB ||
-           hdmi->hdmi_data.enc_out_format == YCBCR444)
-               return 1;
-       return 0;
-}
-
-static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
-{
-       const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
-       unsigned i;
-       u32 csc_scale = 1;
-
-       if (is_color_space_conversion(hdmi)) {
-               if (hdmi->hdmi_data.enc_out_format == RGB) {
-                       if (hdmi->hdmi_data.colorimetry ==
-                                       HDMI_COLORIMETRY_ITU_601)
-                               csc_coeff = &csc_coeff_rgb_out_eitu601;
-                       else
-                               csc_coeff = &csc_coeff_rgb_out_eitu709;
-               } else if (hdmi->hdmi_data.enc_in_format == RGB) {
-                       if (hdmi->hdmi_data.colorimetry ==
-                                       HDMI_COLORIMETRY_ITU_601)
-                               csc_coeff = &csc_coeff_rgb_in_eitu601;
-                       else
-                               csc_coeff = &csc_coeff_rgb_in_eitu709;
-                       csc_scale = 0;
-               }
-       }
-
-       /* The CSC registers are sequential, alternating MSB then LSB */
-       for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) {
-               u16 coeff_a = (*csc_coeff)[0][i];
-               u16 coeff_b = (*csc_coeff)[1][i];
-               u16 coeff_c = (*csc_coeff)[2][i];
-
-               hdmi_writeb(hdmi, coeff_a & 0xff,
-                       HDMI_CSC_COEF_A1_LSB + i * 2);
-               hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
-               hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
-               hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
-               hdmi_writeb(hdmi, coeff_c & 0xff,
-                       HDMI_CSC_COEF_C1_LSB + i * 2);
-               hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
-       }
-
-       hdmi_modb(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK,
-                 HDMI_CSC_SCALE);
-}
-
-static void hdmi_video_csc(struct imx_hdmi *hdmi)
-{
-       int color_depth = 0;
-       int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
-       int decimation = 0;
-
-       /* YCC422 interpolation to 444 mode */
-       if (is_color_space_interpolation(hdmi))
-               interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1;
-       else if (is_color_space_decimation(hdmi))
-               decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3;
-
-       if (hdmi->hdmi_data.enc_color_depth == 8)
-               color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP;
-       else if (hdmi->hdmi_data.enc_color_depth == 10)
-               color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP;
-       else if (hdmi->hdmi_data.enc_color_depth == 12)
-               color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP;
-       else if (hdmi->hdmi_data.enc_color_depth == 16)
-               color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP;
-       else
-               return;
-
-       /* Configure the CSC registers */
-       hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG);
-       hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
-                 HDMI_CSC_SCALE);
-
-       imx_hdmi_update_csc_coeffs(hdmi);
-}
-
-/*
- * HDMI video packetizer is used to packetize the data.
- * for example, if input is YCC422 mode or repeater is used,
- * data should be repacked this module can be bypassed.
- */
-static void hdmi_video_packetize(struct imx_hdmi *hdmi)
-{
-       unsigned int color_depth = 0;
-       unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
-       unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
-       struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
-       u8 val, vp_conf;
-
-       if (hdmi_data->enc_out_format == RGB
-               || hdmi_data->enc_out_format == YCBCR444) {
-               if (!hdmi_data->enc_color_depth)
-                       output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
-               else if (hdmi_data->enc_color_depth == 8) {
-                       color_depth = 4;
-                       output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
-               } else if (hdmi_data->enc_color_depth == 10)
-                       color_depth = 5;
-               else if (hdmi_data->enc_color_depth == 12)
-                       color_depth = 6;
-               else if (hdmi_data->enc_color_depth == 16)
-                       color_depth = 7;
-               else
-                       return;
-       } else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
-               if (!hdmi_data->enc_color_depth ||
-                   hdmi_data->enc_color_depth == 8)
-                       remap_size = HDMI_VP_REMAP_YCC422_16bit;
-               else if (hdmi_data->enc_color_depth == 10)
-                       remap_size = HDMI_VP_REMAP_YCC422_20bit;
-               else if (hdmi_data->enc_color_depth == 12)
-                       remap_size = HDMI_VP_REMAP_YCC422_24bit;
-               else
-                       return;
-               output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
-       } else
-               return;
-
-       /* set the packetizer registers */
-       val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
-               HDMI_VP_PR_CD_COLOR_DEPTH_MASK) |
-               ((hdmi_data->pix_repet_factor <<
-               HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) &
-               HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
-       hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
-
-       hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
-                 HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);
-
-       /* Data from pixel repeater block */
-       if (hdmi_data->pix_repet_factor > 1) {
-               vp_conf = HDMI_VP_CONF_PR_EN_ENABLE |
-                         HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
-       } else { /* data from packetizer block */
-               vp_conf = HDMI_VP_CONF_PR_EN_DISABLE |
-                         HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
-       }
-
-       hdmi_modb(hdmi, vp_conf,
-                 HDMI_VP_CONF_PR_EN_MASK |
-                 HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
-
-       hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
-                 HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);
-
-       hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
-
-       if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
-               vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
-                         HDMI_VP_CONF_PP_EN_ENABLE |
-                         HDMI_VP_CONF_YCC422_EN_DISABLE;
-       } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
-               vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
-                         HDMI_VP_CONF_PP_EN_DISABLE |
-                         HDMI_VP_CONF_YCC422_EN_ENABLE;
-       } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
-               vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE |
-                         HDMI_VP_CONF_PP_EN_DISABLE |
-                         HDMI_VP_CONF_YCC422_EN_DISABLE;
-       } else {
-               return;
-       }
-
-       hdmi_modb(hdmi, vp_conf,
-                 HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK |
-                 HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
-
-       hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
-                       HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE,
-                 HDMI_VP_STUFF_PP_STUFFING_MASK |
-                 HDMI_VP_STUFF_YCC422_STUFFING_MASK, HDMI_VP_STUFF);
-
-       hdmi_modb(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
-                 HDMI_VP_CONF);
-}
-
-static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
-                                               unsigned char bit)
-{
-       hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
-                 HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
-}
-
-static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
-                                               unsigned char bit)
-{
-       hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
-                 HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
-}
-
-static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
-                                               unsigned char bit)
-{
-       hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
-                 HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
-}
-
-static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
-                                               unsigned char bit)
-{
-       hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
-}
-
-static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
-                                               unsigned char bit)
-{
-       hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
-}
-
-static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
-{
-       while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
-               if (msec-- == 0)
-                       return false;
-               udelay(1000);
-       }
-       return true;
-}
-
-static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
-                             unsigned char addr)
-{
-       hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
-       hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
-       hdmi_writeb(hdmi, (unsigned char)(data >> 8),
-               HDMI_PHY_I2CM_DATAO_1_ADDR);
-       hdmi_writeb(hdmi, (unsigned char)(data >> 0),
-               HDMI_PHY_I2CM_DATAO_0_ADDR);
-       hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
-               HDMI_PHY_I2CM_OPERATION_ADDR);
-       hdmi_phy_wait_i2c_done(hdmi, 1000);
-}
-
-static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
-                                    unsigned char addr)
-{
-       __hdmi_phy_i2c_write(hdmi, data, addr);
-       return 0;
-}
-
-static void imx_hdmi_phy_enable_power(struct imx_hdmi *hdmi, u8 enable)
-{
-       hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
-                        HDMI_PHY_CONF0_PDZ_OFFSET,
-                        HDMI_PHY_CONF0_PDZ_MASK);
-}
-
-static void imx_hdmi_phy_enable_tmds(struct imx_hdmi *hdmi, u8 enable)
-{
-       hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
-                        HDMI_PHY_CONF0_ENTMDS_OFFSET,
-                        HDMI_PHY_CONF0_ENTMDS_MASK);
-}
-
-static void imx_hdmi_phy_gen2_pddq(struct imx_hdmi *hdmi, u8 enable)
-{
-       hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
-                        HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
-                        HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
-}
-
-static void imx_hdmi_phy_gen2_txpwron(struct imx_hdmi *hdmi, u8 enable)
-{
-       hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
-                        HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
-                        HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
-}
-
-static void imx_hdmi_phy_sel_data_en_pol(struct imx_hdmi *hdmi, u8 enable)
-{
-       hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
-                        HDMI_PHY_CONF0_SELDATAENPOL_OFFSET,
-                        HDMI_PHY_CONF0_SELDATAENPOL_MASK);
-}
-
-static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
-{
-       hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
-                        HDMI_PHY_CONF0_SELDIPIF_OFFSET,
-                        HDMI_PHY_CONF0_SELDIPIF_MASK);
-}
-
-enum {
-       RES_8,
-       RES_10,
-       RES_12,
-       RES_MAX,
-};
-
-struct mpll_config {
-       unsigned long mpixelclock;
-       struct {
-               u16 cpce;
-               u16 gmp;
-       } res[RES_MAX];
-};
-
-static const struct mpll_config mpll_config[] = {
-       {
-               45250000, {
-                       { 0x01e0, 0x0000 },
-                       { 0x21e1, 0x0000 },
-                       { 0x41e2, 0x0000 }
-               },
-       }, {
-               92500000, {
-                       { 0x0140, 0x0005 },
-                       { 0x2141, 0x0005 },
-                       { 0x4142, 0x0005 },
-               },
-       }, {
-               148500000, {
-                       { 0x00a0, 0x000a },
-                       { 0x20a1, 0x000a },
-                       { 0x40a2, 0x000a },
-               },
-       }, {
-               ~0UL, {
-                       { 0x00a0, 0x000a },
-                       { 0x2001, 0x000f },
-                       { 0x4002, 0x000f },
-               },
-       }
-};
-
-struct curr_ctrl {
-       unsigned long mpixelclock;
-       u16 curr[RES_MAX];
-};
-
-static const struct curr_ctrl curr_ctrl[] = {
-       /*      pixelclk     bpp8    bpp10   bpp12 */
-       {
-                54000000, { 0x091c, 0x091c, 0x06dc },
-       }, {
-                58400000, { 0x091c, 0x06dc, 0x06dc },
-       }, {
-                72000000, { 0x06dc, 0x06dc, 0x091c },
-       }, {
-                74250000, { 0x06dc, 0x0b5c, 0x091c },
-       }, {
-               118800000, { 0x091c, 0x091c, 0x06dc },
-       }, {
-               216000000, { 0x06dc, 0x0b5c, 0x091c },
-       }
-};
-
-static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
-                             unsigned char res, int cscon)
-{
-       unsigned res_idx, i;
-       u8 val, msec;
-
-       if (prep)
-               return -EINVAL;
-
-       switch (res) {
-       case 0: /* color resolution 0 is 8 bit colour depth */
-       case 8:
-               res_idx = RES_8;
-               break;
-       case 10:
-               res_idx = RES_10;
-               break;
-       case 12:
-               res_idx = RES_12;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* Enable csc path */
-       if (cscon)
-               val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH;
-       else
-               val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS;
-
-       hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL);
-
-       /* gen2 tx power off */
-       imx_hdmi_phy_gen2_txpwron(hdmi, 0);
-
-       /* gen2 pddq */
-       imx_hdmi_phy_gen2_pddq(hdmi, 1);
-
-       /* PHY reset */
-       hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
-       hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
-
-       hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
-
-       hdmi_phy_test_clear(hdmi, 1);
-       hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
-                       HDMI_PHY_I2CM_SLAVE_ADDR);
-       hdmi_phy_test_clear(hdmi, 0);
-
-       /* PLL/MPLL Cfg - always match on final entry */
-       for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++)
-               if (hdmi->hdmi_data.video_mode.mpixelclock <=
-                   mpll_config[i].mpixelclock)
-                       break;
-
-       hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06);
-       hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15);
-
-       for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++)
-               if (hdmi->hdmi_data.video_mode.mpixelclock <=
-                   curr_ctrl[i].mpixelclock)
-                       break;
-
-       if (i >= ARRAY_SIZE(curr_ctrl)) {
-               dev_err(hdmi->dev,
-                               "Pixel clock %d - unsupported by HDMI\n",
-                               hdmi->hdmi_data.video_mode.mpixelclock);
-               return -EINVAL;
-       }
-
-       /* CURRCTRL */
-       hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10);
-
-       hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);  /* PLLPHBYCTRL */
-       hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
-       /* RESISTANCE TERM 133Ohm Cfg */
-       hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);  /* TXTERM */
-       /* PREEMP Cgf 0.00 */
-       hdmi_phy_i2c_write(hdmi, 0x800d, 0x09);  /* CKSYMTXCTRL */
-       /* TX/CK LVL 10 */
-       hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E);  /* VLEVCTRL */
-       /* REMOVE CLK TERM */
-       hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);  /* CKCALCTRL */
-
-       imx_hdmi_phy_enable_power(hdmi, 1);
-
-       /* toggle TMDS enable */
-       imx_hdmi_phy_enable_tmds(hdmi, 0);
-       imx_hdmi_phy_enable_tmds(hdmi, 1);
-
-       /* gen2 tx power on */
-       imx_hdmi_phy_gen2_txpwron(hdmi, 1);
-       imx_hdmi_phy_gen2_pddq(hdmi, 0);
-
-       /*Wait for PHY PLL lock */
-       msec = 5;
-       do {
-               val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
-               if (!val)
-                       break;
-
-               if (msec == 0) {
-                       dev_err(hdmi->dev, "PHY PLL not locked\n");
-                       return -ETIMEDOUT;
-               }
-
-               udelay(1000);
-               msec--;
-       } while (1);
-
-       return 0;
-}
-
-static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
-{
-       int i, ret;
-       bool cscon = false;
-
-       /*check csc whether needed activated in HDMI mode */
-       cscon = (is_color_space_conversion(hdmi) &&
-                       !hdmi->hdmi_data.video_mode.mdvi);
-
-       /* HDMI Phy spec says to do the phy initialization sequence twice */
-       for (i = 0; i < 2; i++) {
-               imx_hdmi_phy_sel_data_en_pol(hdmi, 1);
-               imx_hdmi_phy_sel_interface_control(hdmi, 0);
-               imx_hdmi_phy_enable_tmds(hdmi, 0);
-               imx_hdmi_phy_enable_power(hdmi, 0);
-
-               /* Enable CSC */
-               ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
-               if (ret)
-                       return ret;
-       }
-
-       hdmi->phy_enabled = true;
-       return 0;
-}
-
-static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
-{
-       u8 de;
-
-       if (hdmi->hdmi_data.video_mode.mdataenablepolarity)
-               de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
-       else
-               de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
-
-       /* disable rx detect */
-       hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE,
-                 HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0);
-
-       hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG);
-
-       hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE,
-                 HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
-}
-
-static void hdmi_config_AVI(struct imx_hdmi *hdmi)
-{
-       u8 val, pix_fmt, under_scan;
-       u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry;
-       bool aspect_16_9;
-
-       aspect_16_9 = false; /* FIXME */
-
-       /* AVI Data Byte 1 */
-       if (hdmi->hdmi_data.enc_out_format == YCBCR444)
-               pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR444;
-       else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS)
-               pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR422;
-       else
-               pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_RGB;
-
-               under_scan =  HDMI_FC_AVICONF0_SCAN_INFO_NODATA;
-
-       /*
-        * Active format identification data is present in the AVI InfoFrame.
-        * Under scan info, no bar data
-        */
-       val = pix_fmt | under_scan |
-               HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT |
-               HDMI_FC_AVICONF0_BAR_DATA_NO_DATA;
-
-       hdmi_writeb(hdmi, val, HDMI_FC_AVICONF0);
-
-       /* AVI Data Byte 2 -Set the Aspect Ratio */
-       if (aspect_16_9) {
-               act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9;
-               coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9;
-       } else {
-               act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3;
-               coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3;
-       }
-
-       /* Set up colorimetry */
-       if (hdmi->hdmi_data.enc_out_format == XVYCC444) {
-               colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO;
-               if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
-                       ext_colorimetry =
-                               HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
-               else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
-                       ext_colorimetry =
-                               HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709;
-       } else if (hdmi->hdmi_data.enc_out_format != RGB) {
-               if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
-                       colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_SMPTE;
-               else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
-                       colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_ITUR;
-               ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
-       } else { /* Carries no data */
-               colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA;
-               ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
-       }
-
-       val = colorimetry | coded_ratio | act_ratio;
-       hdmi_writeb(hdmi, val, HDMI_FC_AVICONF1);
-
-       /* AVI Data Byte 3 */
-       val = HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA | ext_colorimetry |
-               HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT |
-               HDMI_FC_AVICONF2_SCALING_NONE;
-       hdmi_writeb(hdmi, val, HDMI_FC_AVICONF2);
-
-       /* AVI Data Byte 4 */
-       hdmi_writeb(hdmi, hdmi->vic, HDMI_FC_AVIVID);
-
-       /* AVI Data Byte 5- set up input and output pixel repetition */
-       val = (((hdmi->hdmi_data.video_mode.mpixelrepetitioninput + 1) <<
-               HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET) &
-               HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK) |
-               ((hdmi->hdmi_data.video_mode.mpixelrepetitionoutput <<
-               HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET) &
-               HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK);
-       hdmi_writeb(hdmi, val, HDMI_FC_PRCONF);
-
-       /* IT Content and quantization range = don't care */
-       val = HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS |
-               HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED;
-       hdmi_writeb(hdmi, val, HDMI_FC_AVICONF3);
-
-       /* AVI Data Bytes 6-13 */
-       hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB0);
-       hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB1);
-       hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB0);
-       hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB1);
-       hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB0);
-       hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB1);
-       hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB0);
-       hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1);
-}
-
-static void hdmi_av_composer(struct imx_hdmi *hdmi,
-                            const struct drm_display_mode *mode)
-{
-       u8 inv_val;
-       struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
-       int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
-
-       vmode->mhsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
-       vmode->mvsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
-       vmode->minterlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
-       vmode->mpixelclock = mode->clock * 1000;
-
-       dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
-
-       /* Set up HDMI_FC_INVIDCONF */
-       inv_val = (hdmi->hdmi_data.hdcp_enable ?
-               HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
-               HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
-
-       inv_val |= (vmode->mvsyncpolarity ?
-               HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
-               HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
-
-       inv_val |= (vmode->mhsyncpolarity ?
-               HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
-               HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW);
-
-       inv_val |= (vmode->mdataenablepolarity ?
-               HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
-               HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW);
-
-       if (hdmi->vic == 39)
-               inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH;
-       else
-               inv_val |= (vmode->minterlaced ?
-                       HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH :
-                       HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW);
-
-       inv_val |= (vmode->minterlaced ?
-               HDMI_FC_INVIDCONF_IN_I_P_INTERLACED :
-               HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE);
-
-       inv_val |= (vmode->mdvi ?
-               HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE :
-               HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE);
-
-       hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF);
-
-       /* Set up horizontal active pixel width */
-       hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
-       hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
-
-       /* Set up vertical active lines */
-       hdmi_writeb(hdmi, mode->vdisplay >> 8, HDMI_FC_INVACTV1);
-       hdmi_writeb(hdmi, mode->vdisplay, HDMI_FC_INVACTV0);
-
-       /* Set up horizontal blanking pixel region width */
-       hblank = mode->htotal - mode->hdisplay;
-       hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1);
-       hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0);
-
-       /* Set up vertical blanking pixel region width */
-       vblank = mode->vtotal - mode->vdisplay;
-       hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK);
-
-       /* Set up HSYNC active edge delay width (in pixel clks) */
-       h_de_hs = mode->hsync_start - mode->hdisplay;
-       hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1);
-       hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0);
-
-       /* Set up VSYNC active edge delay (in lines) */
-       v_de_vs = mode->vsync_start - mode->vdisplay;
-       hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY);
-
-       /* Set up HSYNC active pulse width (in pixel clks) */
-       hsync_len = mode->hsync_end - mode->hsync_start;
-       hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
-       hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
-
-       /* Set up VSYNC active edge delay (in lines) */
-       vsync_len = mode->vsync_end - mode->vsync_start;
-       hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
-}
-
-static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
-{
-       if (!hdmi->phy_enabled)
-               return;
-
-       imx_hdmi_phy_enable_tmds(hdmi, 0);
-       imx_hdmi_phy_enable_power(hdmi, 0);
-
-       hdmi->phy_enabled = false;
-}
-
-/* HDMI Initialization Step B.4 */
-static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
-{
-       u8 clkdis;
-
-       /* control period minimum duration */
-       hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR);
-       hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR);
-       hdmi_writeb(hdmi, 1, HDMI_FC_EXCTRLSPAC);
-
-       /* Set to fill TMDS data channels */
-       hdmi_writeb(hdmi, 0x0B, HDMI_FC_CH0PREAM);
-       hdmi_writeb(hdmi, 0x16, HDMI_FC_CH1PREAM);
-       hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM);
-
-       /* Enable pixel clock and tmds data path */
-       clkdis = 0x7F;
-       clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
-       hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
-
-       clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
-       hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
-
-       /* Enable csc path */
-       if (is_color_space_conversion(hdmi)) {
-               clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
-               hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
-       }
-}
-
-static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
-{
-       hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
-}
-
-/* Workaround to clear the overflow condition */
-static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
-{
-       int count;
-       u8 val;
-
-       /* TMDS software reset */
-       hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
-
-       val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
-       if (hdmi->dev_type == IMX6DL_HDMI) {
-               hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
-               return;
-       }
-
-       for (count = 0; count < 4; count++)
-               hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
-}
-
-static void hdmi_enable_overflow_interrupts(struct imx_hdmi *hdmi)
-{
-       hdmi_writeb(hdmi, 0, HDMI_FC_MASK2);
-       hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
-}
-
-static void hdmi_disable_overflow_interrupts(struct imx_hdmi *hdmi)
-{
-       hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
-                   HDMI_IH_MUTE_FC_STAT2);
-}
-
-static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
-{
-       int ret;
-
-       hdmi_disable_overflow_interrupts(hdmi);
-
-       hdmi->vic = drm_match_cea_mode(mode);
-
-       if (!hdmi->vic) {
-               dev_dbg(hdmi->dev, "Non-CEA mode used in HDMI\n");
-               hdmi->hdmi_data.video_mode.mdvi = true;
-       } else {
-               dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic);
-               hdmi->hdmi_data.video_mode.mdvi = false;
-       }
-
-       if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
-               (hdmi->vic == 21) || (hdmi->vic == 22) ||
-               (hdmi->vic == 2) || (hdmi->vic == 3) ||
-               (hdmi->vic == 17) || (hdmi->vic == 18))
-               hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
-       else
-               hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
-
-       if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
-               (hdmi->vic == 12) || (hdmi->vic == 13) ||
-               (hdmi->vic == 14) || (hdmi->vic == 15) ||
-               (hdmi->vic == 25) || (hdmi->vic == 26) ||
-               (hdmi->vic == 27) || (hdmi->vic == 28) ||
-               (hdmi->vic == 29) || (hdmi->vic == 30) ||
-               (hdmi->vic == 35) || (hdmi->vic == 36) ||
-               (hdmi->vic == 37) || (hdmi->vic == 38))
-               hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1;
-       else
-               hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
-
-       hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
-
-       /* TODO: Get input format from IPU (via FB driver interface) */
-       hdmi->hdmi_data.enc_in_format = RGB;
-
-       hdmi->hdmi_data.enc_out_format = RGB;
-
-       hdmi->hdmi_data.enc_color_depth = 8;
-       hdmi->hdmi_data.pix_repet_factor = 0;
-       hdmi->hdmi_data.hdcp_enable = 0;
-       hdmi->hdmi_data.video_mode.mdataenablepolarity = true;
-
-       /* HDMI Initialization Step B.1 */
-       hdmi_av_composer(hdmi, mode);
-
-       /* HDMI Initializateion Step B.2 */
-       ret = imx_hdmi_phy_init(hdmi);
-       if (ret)
-               return ret;
-
-       /* HDMI Initialization Step B.3 */
-       imx_hdmi_enable_video_path(hdmi);
-
-       /* not for DVI mode */
-       if (hdmi->hdmi_data.video_mode.mdvi)
-               dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
-       else {
-               dev_dbg(hdmi->dev, "%s CEA mode\n", __func__);
-
-               /* HDMI Initialization Step E - Configure audio */
-               hdmi_clk_regenerator_update_pixel_clock(hdmi);
-               hdmi_enable_audio_clk(hdmi);
-
-               /* HDMI Initialization Step F - Configure AVI InfoFrame */
-               hdmi_config_AVI(hdmi);
-       }
-
-       hdmi_video_packetize(hdmi);
-       hdmi_video_csc(hdmi);
-       hdmi_video_sample(hdmi);
-       hdmi_tx_hdcp_config(hdmi);
-
-       imx_hdmi_clear_overflow(hdmi);
-       if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi)
-               hdmi_enable_overflow_interrupts(hdmi);
-
-       return 0;
-}
-
-/* Wait until we are registered to enable interrupts */
-static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
-{
-       hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
-                   HDMI_PHY_I2CM_INT_ADDR);
-
-       hdmi_writeb(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
-                   HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
-                   HDMI_PHY_I2CM_CTLINT_ADDR);
-
-       /* enable cable hot plug irq */
-       hdmi_writeb(hdmi, (u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0);
-
-       /* Clear Hotplug interrupts */
-       hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
-
-       return 0;
-}
-
-static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
-{
-       u8 ih_mute;
-
-       /*
-        * Boot up defaults are:
-        * HDMI_IH_MUTE   = 0x03 (disabled)
-        * HDMI_IH_MUTE_* = 0x00 (enabled)
-        *
-        * Disable top level interrupt bits in HDMI block
-        */
-       ih_mute = hdmi_readb(hdmi, HDMI_IH_MUTE) |
-                 HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
-                 HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;
-
-       hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
-
-       /* by default mask all interrupts */
-       hdmi_writeb(hdmi, 0xff, HDMI_VP_MASK);
-       hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK0);
-       hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK1);
-       hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK2);
-       hdmi_writeb(hdmi, 0xff, HDMI_PHY_MASK0);
-       hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_INT_ADDR);
-       hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_CTLINT_ADDR);
-       hdmi_writeb(hdmi, 0xff, HDMI_AUD_INT);
-       hdmi_writeb(hdmi, 0xff, HDMI_AUD_SPDIFINT);
-       hdmi_writeb(hdmi, 0xff, HDMI_AUD_HBR_MASK);
-       hdmi_writeb(hdmi, 0xff, HDMI_GP_MASK);
-       hdmi_writeb(hdmi, 0xff, HDMI_A_APIINTMSK);
-       hdmi_writeb(hdmi, 0xff, HDMI_CEC_MASK);
-       hdmi_writeb(hdmi, 0xff, HDMI_I2CM_INT);
-       hdmi_writeb(hdmi, 0xff, HDMI_I2CM_CTLINT);
-
-       /* Disable interrupts in the IH_MUTE_* registers */
-       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT0);
-       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT1);
-       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT2);
-       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AS_STAT0);
-       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_PHY_STAT0);
-       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CM_STAT0);
-       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_CEC_STAT0);
-       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_VP_STAT0);
-       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CMPHY_STAT0);
-       hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AHBDMAAUD_STAT0);
-
-       /* Enable top level interrupt bits in HDMI block */
-       ih_mute &= ~(HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
-                   HDMI_IH_MUTE_MUTE_ALL_INTERRUPT);
-       hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
-}
-
-static void imx_hdmi_poweron(struct imx_hdmi *hdmi)
-{
-       imx_hdmi_setup(hdmi, &hdmi->previous_mode);
-}
-
-static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
-{
-       imx_hdmi_phy_disable(hdmi);
-}
-
-static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
-                                                       *connector, bool force)
-{
-       struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
-                                            connector);
-
-       return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
-               connector_status_connected : connector_status_disconnected;
-}
-
-static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
-{
-       struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
-                                            connector);
-       struct edid *edid;
-       int ret;
-
-       if (!hdmi->ddc)
-               return 0;
-
-       edid = drm_get_edid(connector, hdmi->ddc);
-       if (edid) {
-               dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
-                       edid->width_cm, edid->height_cm);
-
-               drm_mode_connector_update_edid_property(connector, edid);
-               ret = drm_add_edid_modes(connector, edid);
-               kfree(edid);
-       } else {
-               dev_dbg(hdmi->dev, "failed to get edid\n");
-       }
-
-       return 0;
-}
-
-static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
-                                                          *connector)
-{
-       struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
-                                            connector);
-
-       return &hdmi->encoder;
-}
-
-static void imx_hdmi_encoder_mode_set(struct drm_encoder *encoder,
-                       struct drm_display_mode *mode,
-                       struct drm_display_mode *adjusted_mode)
-{
-       struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
-
-       imx_hdmi_setup(hdmi, mode);
-
-       /* Store the display mode for plugin/DKMS poweron events */
-       memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
-}
-
-static bool imx_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
-                       const struct drm_display_mode *mode,
-                       struct drm_display_mode *adjusted_mode)
-{
-       return true;
-}
-
-static void imx_hdmi_encoder_disable(struct drm_encoder *encoder)
-{
-}
-
-static void imx_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-       struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
-
-       if (mode)
-               imx_hdmi_poweroff(hdmi);
-       else
-               imx_hdmi_poweron(hdmi);
-}
-
-static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
-{
-       struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
-
-       imx_hdmi_poweroff(hdmi);
-       imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
-}
-
-static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
-{
-       struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
-       int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
-
-       imx_hdmi_set_ipu_di_mux(hdmi, mux);
-
-       imx_hdmi_poweron(hdmi);
-}
-
-static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
-       .destroy = imx_drm_encoder_destroy,
-};
-
-static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
-       .dpms = imx_hdmi_encoder_dpms,
-       .prepare = imx_hdmi_encoder_prepare,
-       .commit = imx_hdmi_encoder_commit,
-       .mode_set = imx_hdmi_encoder_mode_set,
-       .mode_fixup = imx_hdmi_encoder_mode_fixup,
-       .disable = imx_hdmi_encoder_disable,
-};
-
-static struct drm_connector_funcs imx_hdmi_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .detect = imx_hdmi_connector_detect,
-       .destroy = imx_drm_connector_destroy,
-};
-
-static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
-       .get_modes = imx_hdmi_connector_get_modes,
-       .best_encoder = imx_hdmi_connector_best_encoder,
-};
-
-static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
-{
-       struct imx_hdmi *hdmi = dev_id;
-       u8 intr_stat;
-
-       intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
-       if (intr_stat)
-               hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
-
-       return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
-}
-
-static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
-{
-       struct imx_hdmi *hdmi = dev_id;
-       u8 intr_stat;
-       u8 phy_int_pol;
-
-       intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
-
-       phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0);
-
-       if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
-               if (phy_int_pol & HDMI_PHY_HPD) {
-                       dev_dbg(hdmi->dev, "EVENT=plugin\n");
-
-                       hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
-
-                       imx_hdmi_poweron(hdmi);
-               } else {
-                       dev_dbg(hdmi->dev, "EVENT=plugout\n");
-
-                       hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
-                               HDMI_PHY_POL0);
-
-                       imx_hdmi_poweroff(hdmi);
-               }
-               drm_helper_hpd_irq_event(hdmi->connector.dev);
-       }
-
-       hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
-       hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
-
-       return IRQ_HANDLED;
-}
-
-static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
-{
-       int ret;
-
-       ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder,
-                                      hdmi->dev->of_node);
-       if (ret)
-               return ret;
-
-       hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
-
-       drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
-       drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
-                        DRM_MODE_ENCODER_TMDS);
-
-       drm_connector_helper_add(&hdmi->connector,
-                       &imx_hdmi_connector_helper_funcs);
-       drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
-                          DRM_MODE_CONNECTOR_HDMIA);
-
-       hdmi->connector.encoder = &hdmi->encoder;
-
-       drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder);
-
-       return 0;
-}
-
-static struct platform_device_id imx_hdmi_devtype[] = {
-       {
-               .name = "imx6q-hdmi",
-               .driver_data = IMX6Q_HDMI,
-       }, {
-               .name = "imx6dl-hdmi",
-               .driver_data = IMX6DL_HDMI,
-       }, { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype);
-
-static const struct of_device_id imx_hdmi_dt_ids[] = {
-{ .compatible = "fsl,imx6q-hdmi", .data = &imx_hdmi_devtype[IMX6Q_HDMI], },
-{ .compatible = "fsl,imx6dl-hdmi", .data = &imx_hdmi_devtype[IMX6DL_HDMI], },
-{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
-
-static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       const struct of_device_id *of_id =
-                               of_match_device(imx_hdmi_dt_ids, dev);
-       struct drm_device *drm = data;
-       struct device_node *np = dev->of_node;
-       struct device_node *ddc_node;
-       struct imx_hdmi *hdmi;
-       struct resource *iores;
-       int ret, irq;
-
-       hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
-       if (!hdmi)
-               return -ENOMEM;
-
-       hdmi->dev = dev;
-       hdmi->sample_rate = 48000;
-       hdmi->ratio = 100;
-
-       if (of_id) {
-               const struct platform_device_id *device_id = of_id->data;
-
-               hdmi->dev_type = device_id->driver_data;
-       }
-
-       ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
-       if (ddc_node) {
-               hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
-               if (!hdmi->ddc)
-                       dev_dbg(hdmi->dev, "failed to read ddc node\n");
-
-               of_node_put(ddc_node);
-       } else {
-               dev_dbg(hdmi->dev, "no ddc property found\n");
-       }
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
-
-       ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
-                                       imx_hdmi_irq, IRQF_SHARED,
-                                       dev_name(dev), hdmi);
-       if (ret)
-               return ret;
-
-       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       hdmi->regs = devm_ioremap_resource(dev, iores);
-       if (IS_ERR(hdmi->regs))
-               return PTR_ERR(hdmi->regs);
-
-       hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
-       if (IS_ERR(hdmi->regmap))
-               return PTR_ERR(hdmi->regmap);
-
-       hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
-       if (IS_ERR(hdmi->isfr_clk)) {
-               ret = PTR_ERR(hdmi->isfr_clk);
-               dev_err(hdmi->dev,
-                       "Unable to get HDMI isfr clk: %d\n", ret);
-               return ret;
-       }
-
-       ret = clk_prepare_enable(hdmi->isfr_clk);
-       if (ret) {
-               dev_err(hdmi->dev,
-                       "Cannot enable HDMI isfr clock: %d\n", ret);
-               return ret;
-       }
-
-       hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
-       if (IS_ERR(hdmi->iahb_clk)) {
-               ret = PTR_ERR(hdmi->iahb_clk);
-               dev_err(hdmi->dev,
-                       "Unable to get HDMI iahb clk: %d\n", ret);
-               goto err_isfr;
-       }
-
-       ret = clk_prepare_enable(hdmi->iahb_clk);
-       if (ret) {
-               dev_err(hdmi->dev,
-                       "Cannot enable HDMI iahb clock: %d\n", ret);
-               goto err_isfr;
-       }
-
-       /* Product and revision IDs */
-       dev_info(dev,
-               "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
-               hdmi_readb(hdmi, HDMI_DESIGN_ID),
-               hdmi_readb(hdmi, HDMI_REVISION_ID),
-               hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
-               hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
-
-       initialize_hdmi_ih_mutes(hdmi);
-
-       /*
-        * To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator
-        * N and cts values before enabling phy
-        */
-       hdmi_init_clk_regenerator(hdmi);
-
-       /*
-        * Configure registers related to HDMI interrupt
-        * generation before registering IRQ.
-        */
-       hdmi_writeb(hdmi, HDMI_PHY_HPD, HDMI_PHY_POL0);
-
-       /* Clear Hotplug interrupts */
-       hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
-
-       ret = imx_hdmi_fb_registered(hdmi);
-       if (ret)
-               goto err_iahb;
-
-       ret = imx_hdmi_register(drm, hdmi);
-       if (ret)
-               goto err_iahb;
-
-       /* Unmute interrupts */
-       hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
-
-       dev_set_drvdata(dev, hdmi);
-
-       return 0;
-
-err_iahb:
-       clk_disable_unprepare(hdmi->iahb_clk);
-err_isfr:
-       clk_disable_unprepare(hdmi->isfr_clk);
-
-       return ret;
-}
-
-static void imx_hdmi_unbind(struct device *dev, struct device *master,
-       void *data)
-{
-       struct imx_hdmi *hdmi = dev_get_drvdata(dev);
-
-       /* Disable all interrupts */
-       hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
-
-       hdmi->connector.funcs->destroy(&hdmi->connector);
-       hdmi->encoder.funcs->destroy(&hdmi->encoder);
-
-       clk_disable_unprepare(hdmi->iahb_clk);
-       clk_disable_unprepare(hdmi->isfr_clk);
-       i2c_put_adapter(hdmi->ddc);
-}
-
-static const struct component_ops hdmi_ops = {
-       .bind   = imx_hdmi_bind,
-       .unbind = imx_hdmi_unbind,
-};
-
-static int imx_hdmi_platform_probe(struct platform_device *pdev)
-{
-       return component_add(&pdev->dev, &hdmi_ops);
-}
-
-static int imx_hdmi_platform_remove(struct platform_device *pdev)
-{
-       component_del(&pdev->dev, &hdmi_ops);
-       return 0;
-}
-
-static struct platform_driver imx_hdmi_driver = {
-       .probe  = imx_hdmi_platform_probe,
-       .remove = imx_hdmi_platform_remove,
-       .driver = {
-               .name = "imx-hdmi",
-               .owner = THIS_MODULE,
-               .of_match_table = imx_hdmi_dt_ids,
-       },
-};
-
-module_platform_driver(imx_hdmi_driver);
-
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-hdmi");
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/staging/imx-drm/imx-hdmi.h
deleted file mode 100644 (file)
index 39b6776..0000000
+++ /dev/null
@@ -1,1032 +0,0 @@
-/*
- * Copyright (C) 2011 Freescale Semiconductor, Inc.
- *
- * 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.
- */
-
-#ifndef __IMX_HDMI_H__
-#define __IMX_HDMI_H__
-
-/* Identification Registers */
-#define HDMI_DESIGN_ID                          0x0000
-#define HDMI_REVISION_ID                        0x0001
-#define HDMI_PRODUCT_ID0                        0x0002
-#define HDMI_PRODUCT_ID1                        0x0003
-#define HDMI_CONFIG0_ID                         0x0004
-#define HDMI_CONFIG1_ID                         0x0005
-#define HDMI_CONFIG2_ID                         0x0006
-#define HDMI_CONFIG3_ID                         0x0007
-
-/* Interrupt Registers */
-#define HDMI_IH_FC_STAT0                        0x0100
-#define HDMI_IH_FC_STAT1                        0x0101
-#define HDMI_IH_FC_STAT2                        0x0102
-#define HDMI_IH_AS_STAT0                        0x0103
-#define HDMI_IH_PHY_STAT0                       0x0104
-#define HDMI_IH_I2CM_STAT0                      0x0105
-#define HDMI_IH_CEC_STAT0                       0x0106
-#define HDMI_IH_VP_STAT0                        0x0107
-#define HDMI_IH_I2CMPHY_STAT0                   0x0108
-#define HDMI_IH_AHBDMAAUD_STAT0                 0x0109
-
-#define HDMI_IH_MUTE_FC_STAT0                   0x0180
-#define HDMI_IH_MUTE_FC_STAT1                   0x0181
-#define HDMI_IH_MUTE_FC_STAT2                   0x0182
-#define HDMI_IH_MUTE_AS_STAT0                   0x0183
-#define HDMI_IH_MUTE_PHY_STAT0                  0x0184
-#define HDMI_IH_MUTE_I2CM_STAT0                 0x0185
-#define HDMI_IH_MUTE_CEC_STAT0                  0x0186
-#define HDMI_IH_MUTE_VP_STAT0                   0x0187
-#define HDMI_IH_MUTE_I2CMPHY_STAT0              0x0188
-#define HDMI_IH_MUTE_AHBDMAAUD_STAT0            0x0189
-#define HDMI_IH_MUTE                            0x01FF
-
-/* Video Sample Registers */
-#define HDMI_TX_INVID0                          0x0200
-#define HDMI_TX_INSTUFFING                      0x0201
-#define HDMI_TX_GYDATA0                         0x0202
-#define HDMI_TX_GYDATA1                         0x0203
-#define HDMI_TX_RCRDATA0                        0x0204
-#define HDMI_TX_RCRDATA1                        0x0205
-#define HDMI_TX_BCBDATA0                        0x0206
-#define HDMI_TX_BCBDATA1                        0x0207
-
-/* Video Packetizer Registers */
-#define HDMI_VP_STATUS                          0x0800
-#define HDMI_VP_PR_CD                           0x0801
-#define HDMI_VP_STUFF                           0x0802
-#define HDMI_VP_REMAP                           0x0803
-#define HDMI_VP_CONF                            0x0804
-#define HDMI_VP_STAT                            0x0805
-#define HDMI_VP_INT                             0x0806
-#define HDMI_VP_MASK                            0x0807
-#define HDMI_VP_POL                             0x0808
-
-/* Frame Composer Registers */
-#define HDMI_FC_INVIDCONF                       0x1000
-#define HDMI_FC_INHACTV0                        0x1001
-#define HDMI_FC_INHACTV1                        0x1002
-#define HDMI_FC_INHBLANK0                       0x1003
-#define HDMI_FC_INHBLANK1                       0x1004
-#define HDMI_FC_INVACTV0                        0x1005
-#define HDMI_FC_INVACTV1                        0x1006
-#define HDMI_FC_INVBLANK                        0x1007
-#define HDMI_FC_HSYNCINDELAY0                   0x1008
-#define HDMI_FC_HSYNCINDELAY1                   0x1009
-#define HDMI_FC_HSYNCINWIDTH0                   0x100A
-#define HDMI_FC_HSYNCINWIDTH1                   0x100B
-#define HDMI_FC_VSYNCINDELAY                    0x100C
-#define HDMI_FC_VSYNCINWIDTH                    0x100D
-#define HDMI_FC_INFREQ0                         0x100E
-#define HDMI_FC_INFREQ1                         0x100F
-#define HDMI_FC_INFREQ2                         0x1010
-#define HDMI_FC_CTRLDUR                         0x1011
-#define HDMI_FC_EXCTRLDUR                       0x1012
-#define HDMI_FC_EXCTRLSPAC                      0x1013
-#define HDMI_FC_CH0PREAM                        0x1014
-#define HDMI_FC_CH1PREAM                        0x1015
-#define HDMI_FC_CH2PREAM                        0x1016
-#define HDMI_FC_AVICONF3                        0x1017
-#define HDMI_FC_GCP                             0x1018
-#define HDMI_FC_AVICONF0                        0x1019
-#define HDMI_FC_AVICONF1                        0x101A
-#define HDMI_FC_AVICONF2                        0x101B
-#define HDMI_FC_AVIVID                          0x101C
-#define HDMI_FC_AVIETB0                         0x101D
-#define HDMI_FC_AVIETB1                         0x101E
-#define HDMI_FC_AVISBB0                         0x101F
-#define HDMI_FC_AVISBB1                         0x1020
-#define HDMI_FC_AVIELB0                         0x1021
-#define HDMI_FC_AVIELB1                         0x1022
-#define HDMI_FC_AVISRB0                         0x1023
-#define HDMI_FC_AVISRB1                         0x1024
-#define HDMI_FC_AUDICONF0                       0x1025
-#define HDMI_FC_AUDICONF1                       0x1026
-#define HDMI_FC_AUDICONF2                       0x1027
-#define HDMI_FC_AUDICONF3                       0x1028
-#define HDMI_FC_VSDIEEEID0                      0x1029
-#define HDMI_FC_VSDSIZE                         0x102A
-#define HDMI_FC_VSDIEEEID1                      0x1030
-#define HDMI_FC_VSDIEEEID2                      0x1031
-#define HDMI_FC_VSDPAYLOAD0                     0x1032
-#define HDMI_FC_VSDPAYLOAD1                     0x1033
-#define HDMI_FC_VSDPAYLOAD2                     0x1034
-#define HDMI_FC_VSDPAYLOAD3                     0x1035
-#define HDMI_FC_VSDPAYLOAD4                     0x1036
-#define HDMI_FC_VSDPAYLOAD5                     0x1037
-#define HDMI_FC_VSDPAYLOAD6                     0x1038
-#define HDMI_FC_VSDPAYLOAD7                     0x1039
-#define HDMI_FC_VSDPAYLOAD8                     0x103A
-#define HDMI_FC_VSDPAYLOAD9                     0x103B
-#define HDMI_FC_VSDPAYLOAD10                    0x103C
-#define HDMI_FC_VSDPAYLOAD11                    0x103D
-#define HDMI_FC_VSDPAYLOAD12                    0x103E
-#define HDMI_FC_VSDPAYLOAD13                    0x103F
-#define HDMI_FC_VSDPAYLOAD14                    0x1040
-#define HDMI_FC_VSDPAYLOAD15                    0x1041
-#define HDMI_FC_VSDPAYLOAD16                    0x1042
-#define HDMI_FC_VSDPAYLOAD17                    0x1043
-#define HDMI_FC_VSDPAYLOAD18                    0x1044
-#define HDMI_FC_VSDPAYLOAD19                    0x1045
-#define HDMI_FC_VSDPAYLOAD20                    0x1046
-#define HDMI_FC_VSDPAYLOAD21                    0x1047
-#define HDMI_FC_VSDPAYLOAD22                    0x1048
-#define HDMI_FC_VSDPAYLOAD23                    0x1049
-#define HDMI_FC_SPDVENDORNAME0                  0x104A
-#define HDMI_FC_SPDVENDORNAME1                  0x104B
-#define HDMI_FC_SPDVENDORNAME2                  0x104C
-#define HDMI_FC_SPDVENDORNAME3                  0x104D
-#define HDMI_FC_SPDVENDORNAME4                  0x104E
-#define HDMI_FC_SPDVENDORNAME5                  0x104F
-#define HDMI_FC_SPDVENDORNAME6                  0x1050
-#define HDMI_FC_SPDVENDORNAME7                  0x1051
-#define HDMI_FC_SDPPRODUCTNAME0                 0x1052
-#define HDMI_FC_SDPPRODUCTNAME1                 0x1053
-#define HDMI_FC_SDPPRODUCTNAME2                 0x1054
-#define HDMI_FC_SDPPRODUCTNAME3                 0x1055
-#define HDMI_FC_SDPPRODUCTNAME4                 0x1056
-#define HDMI_FC_SDPPRODUCTNAME5                 0x1057
-#define HDMI_FC_SDPPRODUCTNAME6                 0x1058
-#define HDMI_FC_SDPPRODUCTNAME7                 0x1059
-#define HDMI_FC_SDPPRODUCTNAME8                 0x105A
-#define HDMI_FC_SDPPRODUCTNAME9                 0x105B
-#define HDMI_FC_SDPPRODUCTNAME10                0x105C
-#define HDMI_FC_SDPPRODUCTNAME11                0x105D
-#define HDMI_FC_SDPPRODUCTNAME12                0x105E
-#define HDMI_FC_SDPPRODUCTNAME13                0x105F
-#define HDMI_FC_SDPPRODUCTNAME14                0x1060
-#define HDMI_FC_SPDPRODUCTNAME15                0x1061
-#define HDMI_FC_SPDDEVICEINF                    0x1062
-#define HDMI_FC_AUDSCONF                        0x1063
-#define HDMI_FC_AUDSSTAT                        0x1064
-#define HDMI_FC_DATACH0FILL                     0x1070
-#define HDMI_FC_DATACH1FILL                     0x1071
-#define HDMI_FC_DATACH2FILL                     0x1072
-#define HDMI_FC_CTRLQHIGH                       0x1073
-#define HDMI_FC_CTRLQLOW                        0x1074
-#define HDMI_FC_ACP0                            0x1075
-#define HDMI_FC_ACP28                           0x1076
-#define HDMI_FC_ACP27                           0x1077
-#define HDMI_FC_ACP26                           0x1078
-#define HDMI_FC_ACP25                           0x1079
-#define HDMI_FC_ACP24                           0x107A
-#define HDMI_FC_ACP23                           0x107B
-#define HDMI_FC_ACP22                           0x107C
-#define HDMI_FC_ACP21                           0x107D
-#define HDMI_FC_ACP20                           0x107E
-#define HDMI_FC_ACP19                           0x107F
-#define HDMI_FC_ACP18                           0x1080
-#define HDMI_FC_ACP17                           0x1081
-#define HDMI_FC_ACP16                           0x1082
-#define HDMI_FC_ACP15                           0x1083
-#define HDMI_FC_ACP14                           0x1084
-#define HDMI_FC_ACP13                           0x1085
-#define HDMI_FC_ACP12                           0x1086
-#define HDMI_FC_ACP11                           0x1087
-#define HDMI_FC_ACP10                           0x1088
-#define HDMI_FC_ACP9                            0x1089
-#define HDMI_FC_ACP8                            0x108A
-#define HDMI_FC_ACP7                            0x108B
-#define HDMI_FC_ACP6                            0x108C
-#define HDMI_FC_ACP5                            0x108D
-#define HDMI_FC_ACP4                            0x108E
-#define HDMI_FC_ACP3                            0x108F
-#define HDMI_FC_ACP2                            0x1090
-#define HDMI_FC_ACP1                            0x1091
-#define HDMI_FC_ISCR1_0                         0x1092
-#define HDMI_FC_ISCR1_16                        0x1093
-#define HDMI_FC_ISCR1_15                        0x1094
-#define HDMI_FC_ISCR1_14                        0x1095
-#define HDMI_FC_ISCR1_13                        0x1096
-#define HDMI_FC_ISCR1_12                        0x1097
-#define HDMI_FC_ISCR1_11                        0x1098
-#define HDMI_FC_ISCR1_10                        0x1099
-#define HDMI_FC_ISCR1_9                         0x109A
-#define HDMI_FC_ISCR1_8                         0x109B
-#define HDMI_FC_ISCR1_7                         0x109C
-#define HDMI_FC_ISCR1_6                         0x109D
-#define HDMI_FC_ISCR1_5                         0x109E
-#define HDMI_FC_ISCR1_4                         0x109F
-#define HDMI_FC_ISCR1_3                         0x10A0
-#define HDMI_FC_ISCR1_2                         0x10A1
-#define HDMI_FC_ISCR1_1                         0x10A2
-#define HDMI_FC_ISCR2_15                        0x10A3
-#define HDMI_FC_ISCR2_14                        0x10A4
-#define HDMI_FC_ISCR2_13                        0x10A5
-#define HDMI_FC_ISCR2_12                        0x10A6
-#define HDMI_FC_ISCR2_11                        0x10A7
-#define HDMI_FC_ISCR2_10                        0x10A8
-#define HDMI_FC_ISCR2_9                         0x10A9
-#define HDMI_FC_ISCR2_8                         0x10AA
-#define HDMI_FC_ISCR2_7                         0x10AB
-#define HDMI_FC_ISCR2_6                         0x10AC
-#define HDMI_FC_ISCR2_5                         0x10AD
-#define HDMI_FC_ISCR2_4                         0x10AE
-#define HDMI_FC_ISCR2_3                         0x10AF
-#define HDMI_FC_ISCR2_2                         0x10B0
-#define HDMI_FC_ISCR2_1                         0x10B1
-#define HDMI_FC_ISCR2_0                         0x10B2
-#define HDMI_FC_DATAUTO0                        0x10B3
-#define HDMI_FC_DATAUTO1                        0x10B4
-#define HDMI_FC_DATAUTO2                        0x10B5
-#define HDMI_FC_DATMAN                          0x10B6
-#define HDMI_FC_DATAUTO3                        0x10B7
-#define HDMI_FC_RDRB0                           0x10B8
-#define HDMI_FC_RDRB1                           0x10B9
-#define HDMI_FC_RDRB2                           0x10BA
-#define HDMI_FC_RDRB3                           0x10BB
-#define HDMI_FC_RDRB4                           0x10BC
-#define HDMI_FC_RDRB5                           0x10BD
-#define HDMI_FC_RDRB6                           0x10BE
-#define HDMI_FC_RDRB7                           0x10BF
-#define HDMI_FC_STAT0                           0x10D0
-#define HDMI_FC_INT0                            0x10D1
-#define HDMI_FC_MASK0                           0x10D2
-#define HDMI_FC_POL0                            0x10D3
-#define HDMI_FC_STAT1                           0x10D4
-#define HDMI_FC_INT1                            0x10D5
-#define HDMI_FC_MASK1                           0x10D6
-#define HDMI_FC_POL1                            0x10D7
-#define HDMI_FC_STAT2                           0x10D8
-#define HDMI_FC_INT2                            0x10D9
-#define HDMI_FC_MASK2                           0x10DA
-#define HDMI_FC_POL2                            0x10DB
-#define HDMI_FC_PRCONF                          0x10E0
-
-#define HDMI_FC_GMD_STAT                        0x1100
-#define HDMI_FC_GMD_EN                          0x1101
-#define HDMI_FC_GMD_UP                          0x1102
-#define HDMI_FC_GMD_CONF                        0x1103
-#define HDMI_FC_GMD_HB                          0x1104
-#define HDMI_FC_GMD_PB0                         0x1105
-#define HDMI_FC_GMD_PB1                         0x1106
-#define HDMI_FC_GMD_PB2                         0x1107
-#define HDMI_FC_GMD_PB3                         0x1108
-#define HDMI_FC_GMD_PB4                         0x1109
-#define HDMI_FC_GMD_PB5                         0x110A
-#define HDMI_FC_GMD_PB6                         0x110B
-#define HDMI_FC_GMD_PB7                         0x110C
-#define HDMI_FC_GMD_PB8                         0x110D
-#define HDMI_FC_GMD_PB9                         0x110E
-#define HDMI_FC_GMD_PB10                        0x110F
-#define HDMI_FC_GMD_PB11                        0x1110
-#define HDMI_FC_GMD_PB12                        0x1111
-#define HDMI_FC_GMD_PB13                        0x1112
-#define HDMI_FC_GMD_PB14                        0x1113
-#define HDMI_FC_GMD_PB15                        0x1114
-#define HDMI_FC_GMD_PB16                        0x1115
-#define HDMI_FC_GMD_PB17                        0x1116
-#define HDMI_FC_GMD_PB18                        0x1117
-#define HDMI_FC_GMD_PB19                        0x1118
-#define HDMI_FC_GMD_PB20                        0x1119
-#define HDMI_FC_GMD_PB21                        0x111A
-#define HDMI_FC_GMD_PB22                        0x111B
-#define HDMI_FC_GMD_PB23                        0x111C
-#define HDMI_FC_GMD_PB24                        0x111D
-#define HDMI_FC_GMD_PB25                        0x111E
-#define HDMI_FC_GMD_PB26                        0x111F
-#define HDMI_FC_GMD_PB27                        0x1120
-
-#define HDMI_FC_DBGFORCE                        0x1200
-#define HDMI_FC_DBGAUD0CH0                      0x1201
-#define HDMI_FC_DBGAUD1CH0                      0x1202
-#define HDMI_FC_DBGAUD2CH0                      0x1203
-#define HDMI_FC_DBGAUD0CH1                      0x1204
-#define HDMI_FC_DBGAUD1CH1                      0x1205
-#define HDMI_FC_DBGAUD2CH1                      0x1206
-#define HDMI_FC_DBGAUD0CH2                      0x1207
-#define HDMI_FC_DBGAUD1CH2                      0x1208
-#define HDMI_FC_DBGAUD2CH2                      0x1209
-#define HDMI_FC_DBGAUD0CH3                      0x120A
-#define HDMI_FC_DBGAUD1CH3                      0x120B
-#define HDMI_FC_DBGAUD2CH3                      0x120C
-#define HDMI_FC_DBGAUD0CH4                      0x120D
-#define HDMI_FC_DBGAUD1CH4                      0x120E
-#define HDMI_FC_DBGAUD2CH4                      0x120F
-#define HDMI_FC_DBGAUD0CH5                      0x1210
-#define HDMI_FC_DBGAUD1CH5                      0x1211
-#define HDMI_FC_DBGAUD2CH5                      0x1212
-#define HDMI_FC_DBGAUD0CH6                      0x1213
-#define HDMI_FC_DBGAUD1CH6                      0x1214
-#define HDMI_FC_DBGAUD2CH6                      0x1215
-#define HDMI_FC_DBGAUD0CH7                      0x1216
-#define HDMI_FC_DBGAUD1CH7                      0x1217
-#define HDMI_FC_DBGAUD2CH7                      0x1218
-#define HDMI_FC_DBGTMDS0                        0x1219
-#define HDMI_FC_DBGTMDS1                        0x121A
-#define HDMI_FC_DBGTMDS2                        0x121B
-
-/* HDMI Source PHY Registers */
-#define HDMI_PHY_CONF0                          0x3000
-#define HDMI_PHY_TST0                           0x3001
-#define HDMI_PHY_TST1                           0x3002
-#define HDMI_PHY_TST2                           0x3003
-#define HDMI_PHY_STAT0                          0x3004
-#define HDMI_PHY_INT0                           0x3005
-#define HDMI_PHY_MASK0                          0x3006
-#define HDMI_PHY_POL0                           0x3007
-
-/* HDMI Master PHY Registers */
-#define HDMI_PHY_I2CM_SLAVE_ADDR                0x3020
-#define HDMI_PHY_I2CM_ADDRESS_ADDR              0x3021
-#define HDMI_PHY_I2CM_DATAO_1_ADDR              0x3022
-#define HDMI_PHY_I2CM_DATAO_0_ADDR              0x3023
-#define HDMI_PHY_I2CM_DATAI_1_ADDR              0x3024
-#define HDMI_PHY_I2CM_DATAI_0_ADDR              0x3025
-#define HDMI_PHY_I2CM_OPERATION_ADDR            0x3026
-#define HDMI_PHY_I2CM_INT_ADDR                  0x3027
-#define HDMI_PHY_I2CM_CTLINT_ADDR               0x3028
-#define HDMI_PHY_I2CM_DIV_ADDR                  0x3029
-#define HDMI_PHY_I2CM_SOFTRSTZ_ADDR             0x302a
-#define HDMI_PHY_I2CM_SS_SCL_HCNT_1_ADDR        0x302b
-#define HDMI_PHY_I2CM_SS_SCL_HCNT_0_ADDR        0x302c
-#define HDMI_PHY_I2CM_SS_SCL_LCNT_1_ADDR        0x302d
-#define HDMI_PHY_I2CM_SS_SCL_LCNT_0_ADDR        0x302e
-#define HDMI_PHY_I2CM_FS_SCL_HCNT_1_ADDR        0x302f
-#define HDMI_PHY_I2CM_FS_SCL_HCNT_0_ADDR        0x3030
-#define HDMI_PHY_I2CM_FS_SCL_LCNT_1_ADDR        0x3031
-#define HDMI_PHY_I2CM_FS_SCL_LCNT_0_ADDR        0x3032
-
-/* Audio Sampler Registers */
-#define HDMI_AUD_CONF0                          0x3100
-#define HDMI_AUD_CONF1                          0x3101
-#define HDMI_AUD_INT                            0x3102
-#define HDMI_AUD_CONF2                          0x3103
-#define HDMI_AUD_N1                             0x3200
-#define HDMI_AUD_N2                             0x3201
-#define HDMI_AUD_N3                             0x3202
-#define HDMI_AUD_CTS1                           0x3203
-#define HDMI_AUD_CTS2                           0x3204
-#define HDMI_AUD_CTS3                           0x3205
-#define HDMI_AUD_INPUTCLKFS                     0x3206
-#define HDMI_AUD_SPDIFINT                      0x3302
-#define HDMI_AUD_CONF0_HBR                      0x3400
-#define HDMI_AUD_HBR_STATUS                     0x3401
-#define HDMI_AUD_HBR_INT                        0x3402
-#define HDMI_AUD_HBR_POL                        0x3403
-#define HDMI_AUD_HBR_MASK                       0x3404
-
-/*
- * Generic Parallel Audio Interface Registers
- * Not used as GPAUD interface is not enabled in hw
- */
-#define HDMI_GP_CONF0                           0x3500
-#define HDMI_GP_CONF1                           0x3501
-#define HDMI_GP_CONF2                           0x3502
-#define HDMI_GP_STAT                            0x3503
-#define HDMI_GP_INT                             0x3504
-#define HDMI_GP_MASK                            0x3505
-#define HDMI_GP_POL                             0x3506
-
-/* Audio DMA Registers */
-#define HDMI_AHB_DMA_CONF0                      0x3600
-#define HDMI_AHB_DMA_START                      0x3601
-#define HDMI_AHB_DMA_STOP                       0x3602
-#define HDMI_AHB_DMA_THRSLD                     0x3603
-#define HDMI_AHB_DMA_STRADDR0                   0x3604
-#define HDMI_AHB_DMA_STRADDR1                   0x3605
-#define HDMI_AHB_DMA_STRADDR2                   0x3606
-#define HDMI_AHB_DMA_STRADDR3                   0x3607
-#define HDMI_AHB_DMA_STPADDR0                   0x3608
-#define HDMI_AHB_DMA_STPADDR1                   0x3609
-#define HDMI_AHB_DMA_STPADDR2                   0x360a
-#define HDMI_AHB_DMA_STPADDR3                   0x360b
-#define HDMI_AHB_DMA_BSTADDR0                   0x360c
-#define HDMI_AHB_DMA_BSTADDR1                   0x360d
-#define HDMI_AHB_DMA_BSTADDR2                   0x360e
-#define HDMI_AHB_DMA_BSTADDR3                   0x360f
-#define HDMI_AHB_DMA_MBLENGTH0                  0x3610
-#define HDMI_AHB_DMA_MBLENGTH1                  0x3611
-#define HDMI_AHB_DMA_STAT                       0x3612
-#define HDMI_AHB_DMA_INT                        0x3613
-#define HDMI_AHB_DMA_MASK                       0x3614
-#define HDMI_AHB_DMA_POL                        0x3615
-#define HDMI_AHB_DMA_CONF1                      0x3616
-#define HDMI_AHB_DMA_BUFFSTAT                   0x3617
-#define HDMI_AHB_DMA_BUFFINT                    0x3618
-#define HDMI_AHB_DMA_BUFFMASK                   0x3619
-#define HDMI_AHB_DMA_BUFFPOL                    0x361a
-
-/* Main Controller Registers */
-#define HDMI_MC_SFRDIV                          0x4000
-#define HDMI_MC_CLKDIS                          0x4001
-#define HDMI_MC_SWRSTZ                          0x4002
-#define HDMI_MC_OPCTRL                          0x4003
-#define HDMI_MC_FLOWCTRL                        0x4004
-#define HDMI_MC_PHYRSTZ                         0x4005
-#define HDMI_MC_LOCKONCLOCK                     0x4006
-#define HDMI_MC_HEACPHY_RST                     0x4007
-
-/* Color Space  Converter Registers */
-#define HDMI_CSC_CFG                            0x4100
-#define HDMI_CSC_SCALE                          0x4101
-#define HDMI_CSC_COEF_A1_MSB                    0x4102
-#define HDMI_CSC_COEF_A1_LSB                    0x4103
-#define HDMI_CSC_COEF_A2_MSB                    0x4104
-#define HDMI_CSC_COEF_A2_LSB                    0x4105
-#define HDMI_CSC_COEF_A3_MSB                    0x4106
-#define HDMI_CSC_COEF_A3_LSB                    0x4107
-#define HDMI_CSC_COEF_A4_MSB                    0x4108
-#define HDMI_CSC_COEF_A4_LSB                    0x4109
-#define HDMI_CSC_COEF_B1_MSB                    0x410A
-#define HDMI_CSC_COEF_B1_LSB                    0x410B
-#define HDMI_CSC_COEF_B2_MSB                    0x410C
-#define HDMI_CSC_COEF_B2_LSB                    0x410D
-#define HDMI_CSC_COEF_B3_MSB                    0x410E
-#define HDMI_CSC_COEF_B3_LSB                    0x410F
-#define HDMI_CSC_COEF_B4_MSB                    0x4110
-#define HDMI_CSC_COEF_B4_LSB                    0x4111
-#define HDMI_CSC_COEF_C1_MSB                    0x4112
-#define HDMI_CSC_COEF_C1_LSB                    0x4113
-#define HDMI_CSC_COEF_C2_MSB                    0x4114
-#define HDMI_CSC_COEF_C2_LSB                    0x4115
-#define HDMI_CSC_COEF_C3_MSB                    0x4116
-#define HDMI_CSC_COEF_C3_LSB                    0x4117
-#define HDMI_CSC_COEF_C4_MSB                    0x4118
-#define HDMI_CSC_COEF_C4_LSB                    0x4119
-
-/* HDCP Encryption Engine Registers */
-#define HDMI_A_HDCPCFG0                         0x5000
-#define HDMI_A_HDCPCFG1                         0x5001
-#define HDMI_A_HDCPOBS0                         0x5002
-#define HDMI_A_HDCPOBS1                         0x5003
-#define HDMI_A_HDCPOBS2                         0x5004
-#define HDMI_A_HDCPOBS3                         0x5005
-#define HDMI_A_APIINTCLR                        0x5006
-#define HDMI_A_APIINTSTAT                       0x5007
-#define HDMI_A_APIINTMSK                        0x5008
-#define HDMI_A_VIDPOLCFG                        0x5009
-#define HDMI_A_OESSWCFG                         0x500A
-#define HDMI_A_TIMER1SETUP0                     0x500B
-#define HDMI_A_TIMER1SETUP1                     0x500C
-#define HDMI_A_TIMER2SETUP0                     0x500D
-#define HDMI_A_TIMER2SETUP1                     0x500E
-#define HDMI_A_100MSCFG                         0x500F
-#define HDMI_A_2SCFG0                           0x5010
-#define HDMI_A_2SCFG1                           0x5011
-#define HDMI_A_5SCFG0                           0x5012
-#define HDMI_A_5SCFG1                           0x5013
-#define HDMI_A_SRMVERLSB                        0x5014
-#define HDMI_A_SRMVERMSB                        0x5015
-#define HDMI_A_SRMCTRL                          0x5016
-#define HDMI_A_SFRSETUP                         0x5017
-#define HDMI_A_I2CHSETUP                        0x5018
-#define HDMI_A_INTSETUP                         0x5019
-#define HDMI_A_PRESETUP                         0x501A
-#define HDMI_A_SRM_BASE                         0x5020
-
-/* CEC Engine Registers */
-#define HDMI_CEC_CTRL                           0x7D00
-#define HDMI_CEC_STAT                           0x7D01
-#define HDMI_CEC_MASK                           0x7D02
-#define HDMI_CEC_POLARITY                       0x7D03
-#define HDMI_CEC_INT                            0x7D04
-#define HDMI_CEC_ADDR_L                         0x7D05
-#define HDMI_CEC_ADDR_H                         0x7D06
-#define HDMI_CEC_TX_CNT                         0x7D07
-#define HDMI_CEC_RX_CNT                         0x7D08
-#define HDMI_CEC_TX_DATA0                       0x7D10
-#define HDMI_CEC_TX_DATA1                       0x7D11
-#define HDMI_CEC_TX_DATA2                       0x7D12
-#define HDMI_CEC_TX_DATA3                       0x7D13
-#define HDMI_CEC_TX_DATA4                       0x7D14
-#define HDMI_CEC_TX_DATA5                       0x7D15
-#define HDMI_CEC_TX_DATA6                       0x7D16
-#define HDMI_CEC_TX_DATA7                       0x7D17
-#define HDMI_CEC_TX_DATA8                       0x7D18
-#define HDMI_CEC_TX_DATA9                       0x7D19
-#define HDMI_CEC_TX_DATA10                      0x7D1a
-#define HDMI_CEC_TX_DATA11                      0x7D1b
-#define HDMI_CEC_TX_DATA12                      0x7D1c
-#define HDMI_CEC_TX_DATA13                      0x7D1d
-#define HDMI_CEC_TX_DATA14                      0x7D1e
-#define HDMI_CEC_TX_DATA15                      0x7D1f
-#define HDMI_CEC_RX_DATA0                       0x7D20
-#define HDMI_CEC_RX_DATA1                       0x7D21
-#define HDMI_CEC_RX_DATA2                       0x7D22
-#define HDMI_CEC_RX_DATA3                       0x7D23
-#define HDMI_CEC_RX_DATA4                       0x7D24
-#define HDMI_CEC_RX_DATA5                       0x7D25
-#define HDMI_CEC_RX_DATA6                       0x7D26
-#define HDMI_CEC_RX_DATA7                       0x7D27
-#define HDMI_CEC_RX_DATA8                       0x7D28
-#define HDMI_CEC_RX_DATA9                       0x7D29
-#define HDMI_CEC_RX_DATA10                      0x7D2a
-#define HDMI_CEC_RX_DATA11                      0x7D2b
-#define HDMI_CEC_RX_DATA12                      0x7D2c
-#define HDMI_CEC_RX_DATA13                      0x7D2d
-#define HDMI_CEC_RX_DATA14                      0x7D2e
-#define HDMI_CEC_RX_DATA15                      0x7D2f
-#define HDMI_CEC_LOCK                           0x7D30
-#define HDMI_CEC_WKUPCTRL                       0x7D31
-
-/* I2C Master Registers (E-DDC) */
-#define HDMI_I2CM_SLAVE                         0x7E00
-#define HDMI_I2CMESS                            0x7E01
-#define HDMI_I2CM_DATAO                         0x7E02
-#define HDMI_I2CM_DATAI                         0x7E03
-#define HDMI_I2CM_OPERATION                     0x7E04
-#define HDMI_I2CM_INT                           0x7E05
-#define HDMI_I2CM_CTLINT                        0x7E06
-#define HDMI_I2CM_DIV                           0x7E07
-#define HDMI_I2CM_SEGADDR                       0x7E08
-#define HDMI_I2CM_SOFTRSTZ                      0x7E09
-#define HDMI_I2CM_SEGPTR                        0x7E0A
-#define HDMI_I2CM_SS_SCL_HCNT_1_ADDR            0x7E0B
-#define HDMI_I2CM_SS_SCL_HCNT_0_ADDR            0x7E0C
-#define HDMI_I2CM_SS_SCL_LCNT_1_ADDR            0x7E0D
-#define HDMI_I2CM_SS_SCL_LCNT_0_ADDR            0x7E0E
-#define HDMI_I2CM_FS_SCL_HCNT_1_ADDR            0x7E0F
-#define HDMI_I2CM_FS_SCL_HCNT_0_ADDR            0x7E10
-#define HDMI_I2CM_FS_SCL_LCNT_1_ADDR            0x7E11
-#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR            0x7E12
-
-enum {
-/* IH_FC_INT2 field values */
-       HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03,
-       HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
-       HDMI_IH_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* IH_FC_STAT2 field values */
-       HDMI_IH_FC_STAT2_OVERFLOW_MASK = 0x03,
-       HDMI_IH_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
-       HDMI_IH_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* IH_PHY_STAT0 field values */
-       HDMI_IH_PHY_STAT0_RX_SENSE3 = 0x20,
-       HDMI_IH_PHY_STAT0_RX_SENSE2 = 0x10,
-       HDMI_IH_PHY_STAT0_RX_SENSE1 = 0x8,
-       HDMI_IH_PHY_STAT0_RX_SENSE0 = 0x4,
-       HDMI_IH_PHY_STAT0_TX_PHY_LOCK = 0x2,
-       HDMI_IH_PHY_STAT0_HPD = 0x1,
-
-/* IH_MUTE_I2CMPHY_STAT0 field values */
-       HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYDONE = 0x2,
-       HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYERROR = 0x1,
-
-/* IH_AHBDMAAUD_STAT0 field values */
-       HDMI_IH_AHBDMAAUD_STAT0_ERROR = 0x20,
-       HDMI_IH_AHBDMAAUD_STAT0_LOST = 0x10,
-       HDMI_IH_AHBDMAAUD_STAT0_RETRY = 0x08,
-       HDMI_IH_AHBDMAAUD_STAT0_DONE = 0x04,
-       HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = 0x02,
-       HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01,
-
-/* IH_MUTE_FC_STAT2 field values */
-       HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK = 0x03,
-       HDMI_IH_MUTE_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
-       HDMI_IH_MUTE_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* IH_MUTE_AHBDMAAUD_STAT0 field values */
-       HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = 0x20,
-       HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = 0x10,
-       HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = 0x08,
-       HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = 0x04,
-       HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = 0x02,
-       HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01,
-
-/* IH_MUTE field values */
-       HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT = 0x2,
-       HDMI_IH_MUTE_MUTE_ALL_INTERRUPT = 0x1,
-
-/* TX_INVID0 field values */
-       HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_MASK = 0x80,
-       HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_ENABLE = 0x80,
-       HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE = 0x00,
-       HDMI_TX_INVID0_VIDEO_MAPPING_MASK = 0x1F,
-       HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET = 0,
-
-/* TX_INSTUFFING field values */
-       HDMI_TX_INSTUFFING_BDBDATA_STUFFING_MASK = 0x4,
-       HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE = 0x4,
-       HDMI_TX_INSTUFFING_BDBDATA_STUFFING_DISABLE = 0x0,
-       HDMI_TX_INSTUFFING_RCRDATA_STUFFING_MASK = 0x2,
-       HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE = 0x2,
-       HDMI_TX_INSTUFFING_RCRDATA_STUFFING_DISABLE = 0x0,
-       HDMI_TX_INSTUFFING_GYDATA_STUFFING_MASK = 0x1,
-       HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE = 0x1,
-       HDMI_TX_INSTUFFING_GYDATA_STUFFING_DISABLE = 0x0,
-
-/* VP_PR_CD field values */
-       HDMI_VP_PR_CD_COLOR_DEPTH_MASK = 0xF0,
-       HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET = 4,
-       HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK = 0x0F,
-       HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET = 0,
-
-/* VP_STUFF field values */
-       HDMI_VP_STUFF_IDEFAULT_PHASE_MASK = 0x20,
-       HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET = 5,
-       HDMI_VP_STUFF_IFIX_PP_TO_LAST_MASK = 0x10,
-       HDMI_VP_STUFF_IFIX_PP_TO_LAST_OFFSET = 4,
-       HDMI_VP_STUFF_ICX_GOTO_P0_ST_MASK = 0x8,
-       HDMI_VP_STUFF_ICX_GOTO_P0_ST_OFFSET = 3,
-       HDMI_VP_STUFF_YCC422_STUFFING_MASK = 0x4,
-       HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE = 0x4,
-       HDMI_VP_STUFF_YCC422_STUFFING_DIRECT_MODE = 0x0,
-       HDMI_VP_STUFF_PP_STUFFING_MASK = 0x2,
-       HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE = 0x2,
-       HDMI_VP_STUFF_PP_STUFFING_DIRECT_MODE = 0x0,
-       HDMI_VP_STUFF_PR_STUFFING_MASK = 0x1,
-       HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE = 0x1,
-       HDMI_VP_STUFF_PR_STUFFING_DIRECT_MODE = 0x0,
-
-/* VP_CONF field values */
-       HDMI_VP_CONF_BYPASS_EN_MASK = 0x40,
-       HDMI_VP_CONF_BYPASS_EN_ENABLE = 0x40,
-       HDMI_VP_CONF_BYPASS_EN_DISABLE = 0x00,
-       HDMI_VP_CONF_PP_EN_ENMASK = 0x20,
-       HDMI_VP_CONF_PP_EN_ENABLE = 0x20,
-       HDMI_VP_CONF_PP_EN_DISABLE = 0x00,
-       HDMI_VP_CONF_PR_EN_MASK = 0x10,
-       HDMI_VP_CONF_PR_EN_ENABLE = 0x10,
-       HDMI_VP_CONF_PR_EN_DISABLE = 0x00,
-       HDMI_VP_CONF_YCC422_EN_MASK = 0x8,
-       HDMI_VP_CONF_YCC422_EN_ENABLE = 0x8,
-       HDMI_VP_CONF_YCC422_EN_DISABLE = 0x0,
-       HDMI_VP_CONF_BYPASS_SELECT_MASK = 0x4,
-       HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER = 0x4,
-       HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER = 0x0,
-       HDMI_VP_CONF_OUTPUT_SELECTOR_MASK = 0x3,
-       HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS = 0x3,
-       HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422 = 0x1,
-       HDMI_VP_CONF_OUTPUT_SELECTOR_PP = 0x0,
-
-/* VP_REMAP field values */
-       HDMI_VP_REMAP_MASK = 0x3,
-       HDMI_VP_REMAP_YCC422_24bit = 0x2,
-       HDMI_VP_REMAP_YCC422_20bit = 0x1,
-       HDMI_VP_REMAP_YCC422_16bit = 0x0,
-
-/* FC_INVIDCONF field values */
-       HDMI_FC_INVIDCONF_HDCP_KEEPOUT_MASK = 0x80,
-       HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE = 0x80,
-       HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE = 0x00,
-       HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_MASK = 0x40,
-       HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH = 0x40,
-       HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW = 0x00,
-       HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_MASK = 0x20,
-       HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH = 0x20,
-       HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW = 0x00,
-       HDMI_FC_INVIDCONF_DE_IN_POLARITY_MASK = 0x10,
-       HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH = 0x10,
-       HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW = 0x00,
-       HDMI_FC_INVIDCONF_DVI_MODEZ_MASK = 0x8,
-       HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE = 0x8,
-       HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE = 0x0,
-       HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_MASK = 0x2,
-       HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH = 0x2,
-       HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW = 0x0,
-       HDMI_FC_INVIDCONF_IN_I_P_MASK = 0x1,
-       HDMI_FC_INVIDCONF_IN_I_P_INTERLACED = 0x1,
-       HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE = 0x0,
-
-/* FC_AUDICONF0 field values */
-       HDMI_FC_AUDICONF0_CC_OFFSET = 4,
-       HDMI_FC_AUDICONF0_CC_MASK = 0x70,
-       HDMI_FC_AUDICONF0_CT_OFFSET = 0,
-       HDMI_FC_AUDICONF0_CT_MASK = 0xF,
-
-/* FC_AUDICONF1 field values */
-       HDMI_FC_AUDICONF1_SS_OFFSET = 3,
-       HDMI_FC_AUDICONF1_SS_MASK = 0x18,
-       HDMI_FC_AUDICONF1_SF_OFFSET = 0,
-       HDMI_FC_AUDICONF1_SF_MASK = 0x7,
-
-/* FC_AUDICONF3 field values */
-       HDMI_FC_AUDICONF3_LFEPBL_OFFSET = 5,
-       HDMI_FC_AUDICONF3_LFEPBL_MASK = 0x60,
-       HDMI_FC_AUDICONF3_DM_INH_OFFSET = 4,
-       HDMI_FC_AUDICONF3_DM_INH_MASK = 0x10,
-       HDMI_FC_AUDICONF3_LSV_OFFSET = 0,
-       HDMI_FC_AUDICONF3_LSV_MASK = 0xF,
-
-/* FC_AUDSCHNLS0 field values */
-       HDMI_FC_AUDSCHNLS0_CGMSA_OFFSET = 4,
-       HDMI_FC_AUDSCHNLS0_CGMSA_MASK = 0x30,
-       HDMI_FC_AUDSCHNLS0_COPYRIGHT_OFFSET = 0,
-       HDMI_FC_AUDSCHNLS0_COPYRIGHT_MASK = 0x01,
-
-/* FC_AUDSCHNLS3-6 field values */
-       HDMI_FC_AUDSCHNLS3_OIEC_CH0_OFFSET = 0,
-       HDMI_FC_AUDSCHNLS3_OIEC_CH0_MASK = 0x0f,
-       HDMI_FC_AUDSCHNLS3_OIEC_CH1_OFFSET = 4,
-       HDMI_FC_AUDSCHNLS3_OIEC_CH1_MASK = 0xf0,
-       HDMI_FC_AUDSCHNLS4_OIEC_CH2_OFFSET = 0,
-       HDMI_FC_AUDSCHNLS4_OIEC_CH2_MASK = 0x0f,
-       HDMI_FC_AUDSCHNLS4_OIEC_CH3_OFFSET = 4,
-       HDMI_FC_AUDSCHNLS4_OIEC_CH3_MASK = 0xf0,
-
-       HDMI_FC_AUDSCHNLS5_OIEC_CH0_OFFSET = 0,
-       HDMI_FC_AUDSCHNLS5_OIEC_CH0_MASK = 0x0f,
-       HDMI_FC_AUDSCHNLS5_OIEC_CH1_OFFSET = 4,
-       HDMI_FC_AUDSCHNLS5_OIEC_CH1_MASK = 0xf0,
-       HDMI_FC_AUDSCHNLS6_OIEC_CH2_OFFSET = 0,
-       HDMI_FC_AUDSCHNLS6_OIEC_CH2_MASK = 0x0f,
-       HDMI_FC_AUDSCHNLS6_OIEC_CH3_OFFSET = 4,
-       HDMI_FC_AUDSCHNLS6_OIEC_CH3_MASK = 0xf0,
-
-/* HDMI_FC_AUDSCHNLS7 field values */
-       HDMI_FC_AUDSCHNLS7_ACCURACY_OFFSET = 4,
-       HDMI_FC_AUDSCHNLS7_ACCURACY_MASK = 0x30,
-
-/* HDMI_FC_AUDSCHNLS8 field values */
-       HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_MASK = 0xf0,
-       HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_OFFSET = 4,
-       HDMI_FC_AUDSCHNLS8_WORDLEGNTH_MASK = 0x0f,
-       HDMI_FC_AUDSCHNLS8_WORDLEGNTH_OFFSET = 0,
-
-/* FC_AUDSCONF field values */
-       HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_MASK = 0xF0,
-       HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_OFFSET = 4,
-       HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK = 0x1,
-       HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_OFFSET = 0,
-       HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1 = 0x1,
-       HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0 = 0x0,
-
-/* FC_STAT2 field values */
-       HDMI_FC_STAT2_OVERFLOW_MASK = 0x03,
-       HDMI_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
-       HDMI_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* FC_INT2 field values */
-       HDMI_FC_INT2_OVERFLOW_MASK = 0x03,
-       HDMI_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
-       HDMI_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* FC_MASK2 field values */
-       HDMI_FC_MASK2_OVERFLOW_MASK = 0x03,
-       HDMI_FC_MASK2_LOW_PRIORITY_OVERFLOW = 0x02,
-       HDMI_FC_MASK2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* FC_PRCONF field values */
-       HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK = 0xF0,
-       HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET = 4,
-       HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK = 0x0F,
-       HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET = 0,
-
-/* FC_AVICONF0-FC_AVICONF3 field values */
-       HDMI_FC_AVICONF0_PIX_FMT_MASK = 0x03,
-       HDMI_FC_AVICONF0_PIX_FMT_RGB = 0x00,
-       HDMI_FC_AVICONF0_PIX_FMT_YCBCR422 = 0x01,
-       HDMI_FC_AVICONF0_PIX_FMT_YCBCR444 = 0x02,
-       HDMI_FC_AVICONF0_ACTIVE_FMT_MASK = 0x40,
-       HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT = 0x40,
-       HDMI_FC_AVICONF0_ACTIVE_FMT_NO_INFO = 0x00,
-       HDMI_FC_AVICONF0_BAR_DATA_MASK = 0x0C,
-       HDMI_FC_AVICONF0_BAR_DATA_NO_DATA = 0x00,
-       HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR = 0x04,
-       HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR = 0x08,
-       HDMI_FC_AVICONF0_BAR_DATA_VERT_HORIZ_BAR = 0x0C,
-       HDMI_FC_AVICONF0_SCAN_INFO_MASK = 0x30,
-       HDMI_FC_AVICONF0_SCAN_INFO_OVERSCAN = 0x10,
-       HDMI_FC_AVICONF0_SCAN_INFO_UNDERSCAN = 0x20,
-       HDMI_FC_AVICONF0_SCAN_INFO_NODATA = 0x00,
-
-       HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_MASK = 0x0F,
-       HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_USE_CODED = 0x08,
-       HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3 = 0x09,
-       HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9 = 0x0A,
-       HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_14_9 = 0x0B,
-       HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_MASK = 0x30,
-       HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_NO_DATA = 0x00,
-       HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3 = 0x10,
-       HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9 = 0x20,
-       HDMI_FC_AVICONF1_COLORIMETRY_MASK = 0xC0,
-       HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA = 0x00,
-       HDMI_FC_AVICONF1_COLORIMETRY_SMPTE = 0x40,
-       HDMI_FC_AVICONF1_COLORIMETRY_ITUR = 0x80,
-       HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO = 0xC0,
-
-       HDMI_FC_AVICONF2_SCALING_MASK = 0x03,
-       HDMI_FC_AVICONF2_SCALING_NONE = 0x00,
-       HDMI_FC_AVICONF2_SCALING_HORIZ = 0x01,
-       HDMI_FC_AVICONF2_SCALING_VERT = 0x02,
-       HDMI_FC_AVICONF2_SCALING_HORIZ_VERT = 0x03,
-       HDMI_FC_AVICONF2_RGB_QUANT_MASK = 0x0C,
-       HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT = 0x00,
-       HDMI_FC_AVICONF2_RGB_QUANT_LIMITED_RANGE = 0x04,
-       HDMI_FC_AVICONF2_RGB_QUANT_FULL_RANGE = 0x08,
-       HDMI_FC_AVICONF2_EXT_COLORIMETRY_MASK = 0x70,
-       HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601 = 0x00,
-       HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709 = 0x10,
-       HDMI_FC_AVICONF2_EXT_COLORIMETRY_SYCC601 = 0x20,
-       HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_YCC601 = 0x30,
-       HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_RGB = 0x40,
-       HDMI_FC_AVICONF2_IT_CONTENT_MASK = 0x80,
-       HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA = 0x00,
-       HDMI_FC_AVICONF2_IT_CONTENT_VALID = 0x80,
-
-       HDMI_FC_AVICONF3_IT_CONTENT_TYPE_MASK = 0x03,
-       HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS = 0x00,
-       HDMI_FC_AVICONF3_IT_CONTENT_TYPE_PHOTO = 0x01,
-       HDMI_FC_AVICONF3_IT_CONTENT_TYPE_CINEMA = 0x02,
-       HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GAME = 0x03,
-       HDMI_FC_AVICONF3_QUANT_RANGE_MASK = 0x0C,
-       HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED = 0x00,
-       HDMI_FC_AVICONF3_QUANT_RANGE_FULL = 0x04,
-
-/* FC_DBGFORCE field values */
-       HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10,
-       HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1,
-
-/* PHY_CONF0 field values */
-       HDMI_PHY_CONF0_PDZ_MASK = 0x80,
-       HDMI_PHY_CONF0_PDZ_OFFSET = 7,
-       HDMI_PHY_CONF0_ENTMDS_MASK = 0x40,
-       HDMI_PHY_CONF0_ENTMDS_OFFSET = 6,
-       HDMI_PHY_CONF0_SPARECTRL = 0x20,
-       HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10,
-       HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4,
-       HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8,
-       HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET = 3,
-       HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_MASK = 0x4,
-       HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_OFFSET = 2,
-       HDMI_PHY_CONF0_SELDATAENPOL_MASK = 0x2,
-       HDMI_PHY_CONF0_SELDATAENPOL_OFFSET = 1,
-       HDMI_PHY_CONF0_SELDIPIF_MASK = 0x1,
-       HDMI_PHY_CONF0_SELDIPIF_OFFSET = 0,
-
-/* PHY_TST0 field values */
-       HDMI_PHY_TST0_TSTCLR_MASK = 0x20,
-       HDMI_PHY_TST0_TSTCLR_OFFSET = 5,
-       HDMI_PHY_TST0_TSTEN_MASK = 0x10,
-       HDMI_PHY_TST0_TSTEN_OFFSET = 4,
-       HDMI_PHY_TST0_TSTCLK_MASK = 0x1,
-       HDMI_PHY_TST0_TSTCLK_OFFSET = 0,
-
-/* PHY_STAT0 field values */
-       HDMI_PHY_RX_SENSE3 = 0x80,
-       HDMI_PHY_RX_SENSE2 = 0x40,
-       HDMI_PHY_RX_SENSE1 = 0x20,
-       HDMI_PHY_RX_SENSE0 = 0x10,
-       HDMI_PHY_HPD = 0x02,
-       HDMI_PHY_TX_PHY_LOCK = 0x01,
-
-/* PHY_I2CM_SLAVE_ADDR field values */
-       HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2 = 0x69,
-       HDMI_PHY_I2CM_SLAVE_ADDR_HEAC_PHY = 0x49,
-
-/* PHY_I2CM_OPERATION_ADDR field values */
-       HDMI_PHY_I2CM_OPERATION_ADDR_WRITE = 0x10,
-       HDMI_PHY_I2CM_OPERATION_ADDR_READ = 0x1,
-
-/* HDMI_PHY_I2CM_INT_ADDR */
-       HDMI_PHY_I2CM_INT_ADDR_DONE_POL = 0x08,
-       HDMI_PHY_I2CM_INT_ADDR_DONE_MASK = 0x04,
-
-/* HDMI_PHY_I2CM_CTLINT_ADDR */
-       HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL = 0x80,
-       HDMI_PHY_I2CM_CTLINT_ADDR_NAC_MASK = 0x40,
-       HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL = 0x08,
-       HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_MASK = 0x04,
-
-/* AUD_CTS3 field values */
-       HDMI_AUD_CTS3_N_SHIFT_OFFSET = 5,
-       HDMI_AUD_CTS3_N_SHIFT_MASK = 0xe0,
-       HDMI_AUD_CTS3_N_SHIFT_1 = 0,
-       HDMI_AUD_CTS3_N_SHIFT_16 = 0x20,
-       HDMI_AUD_CTS3_N_SHIFT_32 = 0x40,
-       HDMI_AUD_CTS3_N_SHIFT_64 = 0x60,
-       HDMI_AUD_CTS3_N_SHIFT_128 = 0x80,
-       HDMI_AUD_CTS3_N_SHIFT_256 = 0xa0,
-       /* note that the CTS3 MANUAL bit has been removed
-          from our part. Can't set it, will read as 0. */
-       HDMI_AUD_CTS3_CTS_MANUAL = 0x10,
-       HDMI_AUD_CTS3_AUDCTS19_16_MASK = 0x0f,
-
-/* AHB_DMA_CONF0 field values */
-       HDMI_AHB_DMA_CONF0_SW_FIFO_RST_OFFSET = 7,
-       HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK = 0x80,
-       HDMI_AHB_DMA_CONF0_HBR = 0x10,
-       HDMI_AHB_DMA_CONF0_EN_HLOCK_OFFSET = 3,
-       HDMI_AHB_DMA_CONF0_EN_HLOCK_MASK = 0x08,
-       HDMI_AHB_DMA_CONF0_INCR_TYPE_OFFSET = 1,
-       HDMI_AHB_DMA_CONF0_INCR_TYPE_MASK = 0x06,
-       HDMI_AHB_DMA_CONF0_INCR4 = 0x0,
-       HDMI_AHB_DMA_CONF0_INCR8 = 0x2,
-       HDMI_AHB_DMA_CONF0_INCR16 = 0x4,
-       HDMI_AHB_DMA_CONF0_BURST_MODE = 0x1,
-
-/* HDMI_AHB_DMA_START field values */
-       HDMI_AHB_DMA_START_START_OFFSET = 0,
-       HDMI_AHB_DMA_START_START_MASK = 0x01,
-
-/* HDMI_AHB_DMA_STOP field values */
-       HDMI_AHB_DMA_STOP_STOP_OFFSET = 0,
-       HDMI_AHB_DMA_STOP_STOP_MASK = 0x01,
-
-/* AHB_DMA_STAT, AHB_DMA_INT, AHB_DMA_MASK, AHB_DMA_POL field values */
-       HDMI_AHB_DMA_DONE = 0x80,
-       HDMI_AHB_DMA_RETRY_SPLIT = 0x40,
-       HDMI_AHB_DMA_LOSTOWNERSHIP = 0x20,
-       HDMI_AHB_DMA_ERROR = 0x10,
-       HDMI_AHB_DMA_FIFO_THREMPTY = 0x04,
-       HDMI_AHB_DMA_FIFO_FULL = 0x02,
-       HDMI_AHB_DMA_FIFO_EMPTY = 0x01,
-
-/* AHB_DMA_BUFFSTAT, AHB_DMA_BUFFINT,AHB_DMA_BUFFMASK,AHB_DMA_BUFFPOL values */
-       HDMI_AHB_DMA_BUFFSTAT_FULL = 0x02,
-       HDMI_AHB_DMA_BUFFSTAT_EMPTY = 0x01,
-
-/* MC_CLKDIS field values */
-       HDMI_MC_CLKDIS_HDCPCLK_DISABLE = 0x40,
-       HDMI_MC_CLKDIS_CECCLK_DISABLE = 0x20,
-       HDMI_MC_CLKDIS_CSCCLK_DISABLE = 0x10,
-       HDMI_MC_CLKDIS_AUDCLK_DISABLE = 0x8,
-       HDMI_MC_CLKDIS_PREPCLK_DISABLE = 0x4,
-       HDMI_MC_CLKDIS_TMDSCLK_DISABLE = 0x2,
-       HDMI_MC_CLKDIS_PIXELCLK_DISABLE = 0x1,
-
-/* MC_SWRSTZ field values */
-       HDMI_MC_SWRSTZ_TMDSSWRST_REQ = 0x02,
-
-/* MC_FLOWCTRL field values */
-       HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_MASK = 0x1,
-       HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH = 0x1,
-       HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS = 0x0,
-
-/* MC_PHYRSTZ field values */
-       HDMI_MC_PHYRSTZ_ASSERT = 0x0,
-       HDMI_MC_PHYRSTZ_DEASSERT = 0x1,
-
-/* MC_HEACPHY_RST field values */
-       HDMI_MC_HEACPHY_RST_ASSERT = 0x1,
-       HDMI_MC_HEACPHY_RST_DEASSERT = 0x0,
-
-/* CSC_CFG field values */
-       HDMI_CSC_CFG_INTMODE_MASK = 0x30,
-       HDMI_CSC_CFG_INTMODE_OFFSET = 4,
-       HDMI_CSC_CFG_INTMODE_DISABLE = 0x00,
-       HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1 = 0x10,
-       HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA2 = 0x20,
-       HDMI_CSC_CFG_DECMODE_MASK = 0x3,
-       HDMI_CSC_CFG_DECMODE_OFFSET = 0,
-       HDMI_CSC_CFG_DECMODE_DISABLE = 0x0,
-       HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA1 = 0x1,
-       HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA2 = 0x2,
-       HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3 = 0x3,
-
-/* CSC_SCALE field values */
-       HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK = 0xF0,
-       HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP = 0x00,
-       HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP = 0x50,
-       HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP = 0x60,
-       HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP = 0x70,
-       HDMI_CSC_SCALE_CSCSCALE_MASK = 0x03,
-
-/* A_HDCPCFG0 field values */
-       HDMI_A_HDCPCFG0_ELVENA_MASK = 0x80,
-       HDMI_A_HDCPCFG0_ELVENA_ENABLE = 0x80,
-       HDMI_A_HDCPCFG0_ELVENA_DISABLE = 0x00,
-       HDMI_A_HDCPCFG0_I2CFASTMODE_MASK = 0x40,
-       HDMI_A_HDCPCFG0_I2CFASTMODE_ENABLE = 0x40,
-       HDMI_A_HDCPCFG0_I2CFASTMODE_DISABLE = 0x00,
-       HDMI_A_HDCPCFG0_BYPENCRYPTION_MASK = 0x20,
-       HDMI_A_HDCPCFG0_BYPENCRYPTION_ENABLE = 0x20,
-       HDMI_A_HDCPCFG0_BYPENCRYPTION_DISABLE = 0x00,
-       HDMI_A_HDCPCFG0_SYNCRICHECK_MASK = 0x10,
-       HDMI_A_HDCPCFG0_SYNCRICHECK_ENABLE = 0x10,
-       HDMI_A_HDCPCFG0_SYNCRICHECK_DISABLE = 0x00,
-       HDMI_A_HDCPCFG0_AVMUTE_MASK = 0x8,
-       HDMI_A_HDCPCFG0_AVMUTE_ENABLE = 0x8,
-       HDMI_A_HDCPCFG0_AVMUTE_DISABLE = 0x0,
-       HDMI_A_HDCPCFG0_RXDETECT_MASK = 0x4,
-       HDMI_A_HDCPCFG0_RXDETECT_ENABLE = 0x4,
-       HDMI_A_HDCPCFG0_RXDETECT_DISABLE = 0x0,
-       HDMI_A_HDCPCFG0_EN11FEATURE_MASK = 0x2,
-       HDMI_A_HDCPCFG0_EN11FEATURE_ENABLE = 0x2,
-       HDMI_A_HDCPCFG0_EN11FEATURE_DISABLE = 0x0,
-       HDMI_A_HDCPCFG0_HDMIDVI_MASK = 0x1,
-       HDMI_A_HDCPCFG0_HDMIDVI_HDMI = 0x1,
-       HDMI_A_HDCPCFG0_HDMIDVI_DVI = 0x0,
-
-/* A_HDCPCFG1 field values */
-       HDMI_A_HDCPCFG1_DISSHA1CHECK_MASK = 0x8,
-       HDMI_A_HDCPCFG1_DISSHA1CHECK_DISABLE = 0x8,
-       HDMI_A_HDCPCFG1_DISSHA1CHECK_ENABLE = 0x0,
-       HDMI_A_HDCPCFG1_PH2UPSHFTENC_MASK = 0x4,
-       HDMI_A_HDCPCFG1_PH2UPSHFTENC_ENABLE = 0x4,
-       HDMI_A_HDCPCFG1_PH2UPSHFTENC_DISABLE = 0x0,
-       HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK = 0x2,
-       HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE = 0x2,
-       HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_ENABLE = 0x0,
-       HDMI_A_HDCPCFG1_SWRESET_MASK = 0x1,
-       HDMI_A_HDCPCFG1_SWRESET_ASSERT = 0x0,
-
-/* A_VIDPOLCFG field values */
-       HDMI_A_VIDPOLCFG_UNENCRYPTCONF_MASK = 0x60,
-       HDMI_A_VIDPOLCFG_UNENCRYPTCONF_OFFSET = 5,
-       HDMI_A_VIDPOLCFG_DATAENPOL_MASK = 0x10,
-       HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH = 0x10,
-       HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW = 0x0,
-       HDMI_A_VIDPOLCFG_VSYNCPOL_MASK = 0x8,
-       HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_HIGH = 0x8,
-       HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_LOW = 0x0,
-       HDMI_A_VIDPOLCFG_HSYNCPOL_MASK = 0x2,
-       HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2,
-       HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
-};
-#endif /* __IMX_HDMI_H__ */
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
deleted file mode 100644 (file)
index 4662e00..0000000
+++ /dev/null
@@ -1,616 +0,0 @@
-/*
- * i.MX drm driver - LVDS display bridge
- *
- * Copyright (C) 2012 Sascha Hauer, Pengutronix
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
-
-#include <linux/module.h>
-#include <linux/clk.h>
-#include <linux/component.h>
-#include <drm/drmP.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_crtc_helper.h>
-#include <linux/mfd/syscon.h>
-#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <video/of_videomode.h>
-#include <linux/regmap.h>
-#include <linux/videodev2.h>
-
-#include "imx-drm.h"
-
-#define DRIVER_NAME "imx-ldb"
-
-#define LDB_CH0_MODE_EN_TO_DI0         (1 << 0)
-#define LDB_CH0_MODE_EN_TO_DI1         (3 << 0)
-#define LDB_CH0_MODE_EN_MASK           (3 << 0)
-#define LDB_CH1_MODE_EN_TO_DI0         (1 << 2)
-#define LDB_CH1_MODE_EN_TO_DI1         (3 << 2)
-#define LDB_CH1_MODE_EN_MASK           (3 << 2)
-#define LDB_SPLIT_MODE_EN              (1 << 4)
-#define LDB_DATA_WIDTH_CH0_24          (1 << 5)
-#define LDB_BIT_MAP_CH0_JEIDA          (1 << 6)
-#define LDB_DATA_WIDTH_CH1_24          (1 << 7)
-#define LDB_BIT_MAP_CH1_JEIDA          (1 << 8)
-#define LDB_DI0_VS_POL_ACT_LOW         (1 << 9)
-#define LDB_DI1_VS_POL_ACT_LOW         (1 << 10)
-#define LDB_BGREF_RMODE_INT            (1 << 15)
-
-#define con_to_imx_ldb_ch(x) container_of(x, struct imx_ldb_channel, connector)
-#define enc_to_imx_ldb_ch(x) container_of(x, struct imx_ldb_channel, encoder)
-
-struct imx_ldb;
-
-struct imx_ldb_channel {
-       struct imx_ldb *ldb;
-       struct drm_connector connector;
-       struct drm_encoder encoder;
-       struct device_node *child;
-       int chno;
-       void *edid;
-       int edid_len;
-       struct drm_display_mode mode;
-       int mode_valid;
-};
-
-struct bus_mux {
-       int reg;
-       int shift;
-       int mask;
-};
-
-struct imx_ldb {
-       struct regmap *regmap;
-       struct device *dev;
-       struct imx_ldb_channel channel[2];
-       struct clk *clk[2]; /* our own clock */
-       struct clk *clk_sel[4]; /* parent of display clock */
-       struct clk *clk_pll[2]; /* upstream clock we can adjust */
-       u32 ldb_ctrl;
-       const struct bus_mux *lvds_mux;
-};
-
-static enum drm_connector_status imx_ldb_connector_detect(
-               struct drm_connector *connector, bool force)
-{
-       return connector_status_connected;
-}
-
-static int imx_ldb_connector_get_modes(struct drm_connector *connector)
-{
-       struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
-       int num_modes = 0;
-
-       if (imx_ldb_ch->edid) {
-               drm_mode_connector_update_edid_property(connector,
-                                                       imx_ldb_ch->edid);
-               num_modes = drm_add_edid_modes(connector, imx_ldb_ch->edid);
-       }
-
-       if (imx_ldb_ch->mode_valid) {
-               struct drm_display_mode *mode;
-
-               mode = drm_mode_create(connector->dev);
-               if (!mode)
-                       return -EINVAL;
-               drm_mode_copy(mode, &imx_ldb_ch->mode);
-               mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
-               drm_mode_probed_add(connector, mode);
-               num_modes++;
-       }
-
-       return num_modes;
-}
-
-static struct drm_encoder *imx_ldb_connector_best_encoder(
-               struct drm_connector *connector)
-{
-       struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
-
-       return &imx_ldb_ch->encoder;
-}
-
-static void imx_ldb_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-}
-
-static bool imx_ldb_encoder_mode_fixup(struct drm_encoder *encoder,
-                          const struct drm_display_mode *mode,
-                          struct drm_display_mode *adjusted_mode)
-{
-       return true;
-}
-
-static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno,
-               unsigned long serial_clk, unsigned long di_clk)
-{
-       int ret;
-
-       dev_dbg(ldb->dev, "%s: now: %ld want: %ld\n", __func__,
-                       clk_get_rate(ldb->clk_pll[chno]), serial_clk);
-       clk_set_rate(ldb->clk_pll[chno], serial_clk);
-
-       dev_dbg(ldb->dev, "%s after: %ld\n", __func__,
-                       clk_get_rate(ldb->clk_pll[chno]));
-
-       dev_dbg(ldb->dev, "%s: now: %ld want: %ld\n", __func__,
-                       clk_get_rate(ldb->clk[chno]),
-                       (long int)di_clk);
-       clk_set_rate(ldb->clk[chno], di_clk);
-
-       dev_dbg(ldb->dev, "%s after: %ld\n", __func__,
-                       clk_get_rate(ldb->clk[chno]));
-
-       /* set display clock mux to LDB input clock */
-       ret = clk_set_parent(ldb->clk_sel[mux], ldb->clk[chno]);
-       if (ret)
-               dev_err(ldb->dev,
-                       "unable to set di%d parent clock to ldb_di%d\n", mux,
-                       chno);
-}
-
-static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
-{
-       struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
-       struct imx_ldb *ldb = imx_ldb_ch->ldb;
-       struct drm_display_mode *mode = &encoder->crtc->mode;
-       u32 pixel_fmt;
-       unsigned long serial_clk;
-       unsigned long di_clk = mode->clock * 1000;
-       int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
-
-       if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
-               /* dual channel LVDS mode */
-               serial_clk = 3500UL * mode->clock;
-               imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk);
-               imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk);
-       } else {
-               serial_clk = 7000UL * mode->clock;
-               imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk,
-                               di_clk);
-       }
-
-       switch (imx_ldb_ch->chno) {
-       case 0:
-               pixel_fmt = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH0_24) ?
-                       V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666;
-               break;
-       case 1:
-               pixel_fmt = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH1_24) ?
-                       V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666;
-               break;
-       default:
-               dev_err(ldb->dev, "unable to config di%d panel format\n",
-                       imx_ldb_ch->chno);
-               pixel_fmt = V4L2_PIX_FMT_RGB24;
-       }
-
-       imx_drm_panel_format(encoder, pixel_fmt);
-}
-
-static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
-{
-       struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
-       struct imx_ldb *ldb = imx_ldb_ch->ldb;
-       int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
-       int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
-
-       if (dual) {
-               clk_prepare_enable(ldb->clk[0]);
-               clk_prepare_enable(ldb->clk[1]);
-       }
-
-       if (imx_ldb_ch == &ldb->channel[0] || dual) {
-               ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
-               if (mux == 0 || ldb->lvds_mux)
-                       ldb->ldb_ctrl |= LDB_CH0_MODE_EN_TO_DI0;
-               else if (mux == 1)
-                       ldb->ldb_ctrl |= LDB_CH0_MODE_EN_TO_DI1;
-       }
-       if (imx_ldb_ch == &ldb->channel[1] || dual) {
-               ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK;
-               if (mux == 1 || ldb->lvds_mux)
-                       ldb->ldb_ctrl |= LDB_CH1_MODE_EN_TO_DI1;
-               else if (mux == 0)
-                       ldb->ldb_ctrl |= LDB_CH1_MODE_EN_TO_DI0;
-       }
-
-       if (ldb->lvds_mux) {
-               const struct bus_mux *lvds_mux = NULL;
-
-               if (imx_ldb_ch == &ldb->channel[0])
-                       lvds_mux = &ldb->lvds_mux[0];
-               else if (imx_ldb_ch == &ldb->channel[1])
-                       lvds_mux = &ldb->lvds_mux[1];
-
-               regmap_update_bits(ldb->regmap, lvds_mux->reg, lvds_mux->mask,
-                                  mux << lvds_mux->shift);
-       }
-
-       regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
-}
-
-static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
-                        struct drm_display_mode *mode,
-                        struct drm_display_mode *adjusted_mode)
-{
-       struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
-       struct imx_ldb *ldb = imx_ldb_ch->ldb;
-       int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
-
-       if (mode->clock > 170000) {
-               dev_warn(ldb->dev,
-                        "%s: mode exceeds 170 MHz pixel clock\n", __func__);
-       }
-       if (mode->clock > 85000 && !dual) {
-               dev_warn(ldb->dev,
-                        "%s: mode exceeds 85 MHz pixel clock\n", __func__);
-       }
-
-       /* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */
-       if (imx_ldb_ch == &ldb->channel[0]) {
-               if (mode->flags & DRM_MODE_FLAG_NVSYNC)
-                       ldb->ldb_ctrl |= LDB_DI0_VS_POL_ACT_LOW;
-               else if (mode->flags & DRM_MODE_FLAG_PVSYNC)
-                       ldb->ldb_ctrl &= ~LDB_DI0_VS_POL_ACT_LOW;
-       }
-       if (imx_ldb_ch == &ldb->channel[1]) {
-               if (mode->flags & DRM_MODE_FLAG_NVSYNC)
-                       ldb->ldb_ctrl |= LDB_DI1_VS_POL_ACT_LOW;
-               else if (mode->flags & DRM_MODE_FLAG_PVSYNC)
-                       ldb->ldb_ctrl &= ~LDB_DI1_VS_POL_ACT_LOW;
-       }
-}
-
-static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
-{
-       struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
-       struct imx_ldb *ldb = imx_ldb_ch->ldb;
-
-       /*
-        * imx_ldb_encoder_disable is called by
-        * drm_helper_disable_unused_functions without
-        * the encoder being enabled before.
-        */
-       if (imx_ldb_ch == &ldb->channel[0] &&
-           (ldb->ldb_ctrl & LDB_CH0_MODE_EN_MASK) == 0)
-               return;
-       else if (imx_ldb_ch == &ldb->channel[1] &&
-                (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0)
-               return;
-
-       if (imx_ldb_ch == &ldb->channel[0])
-               ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
-       else if (imx_ldb_ch == &ldb->channel[1])
-               ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK;
-
-       regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
-
-       if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
-               clk_disable_unprepare(ldb->clk[0]);
-               clk_disable_unprepare(ldb->clk[1]);
-       }
-}
-
-static struct drm_connector_funcs imx_ldb_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .detect = imx_ldb_connector_detect,
-       .destroy = imx_drm_connector_destroy,
-};
-
-static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
-       .get_modes = imx_ldb_connector_get_modes,
-       .best_encoder = imx_ldb_connector_best_encoder,
-};
-
-static struct drm_encoder_funcs imx_ldb_encoder_funcs = {
-       .destroy = imx_drm_encoder_destroy,
-};
-
-static struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = {
-       .dpms = imx_ldb_encoder_dpms,
-       .mode_fixup = imx_ldb_encoder_mode_fixup,
-       .prepare = imx_ldb_encoder_prepare,
-       .commit = imx_ldb_encoder_commit,
-       .mode_set = imx_ldb_encoder_mode_set,
-       .disable = imx_ldb_encoder_disable,
-};
-
-static int imx_ldb_get_clk(struct imx_ldb *ldb, int chno)
-{
-       char clkname[16];
-
-       snprintf(clkname, sizeof(clkname), "di%d", chno);
-       ldb->clk[chno] = devm_clk_get(ldb->dev, clkname);
-       if (IS_ERR(ldb->clk[chno]))
-               return PTR_ERR(ldb->clk[chno]);
-
-       snprintf(clkname, sizeof(clkname), "di%d_pll", chno);
-       ldb->clk_pll[chno] = devm_clk_get(ldb->dev, clkname);
-
-       return PTR_ERR_OR_ZERO(ldb->clk_pll[chno]);
-}
-
-static int imx_ldb_register(struct drm_device *drm,
-       struct imx_ldb_channel *imx_ldb_ch)
-{
-       struct imx_ldb *ldb = imx_ldb_ch->ldb;
-       int ret;
-
-       ret = imx_drm_encoder_parse_of(drm, &imx_ldb_ch->encoder,
-                                      imx_ldb_ch->child);
-       if (ret)
-               return ret;
-
-       ret = imx_ldb_get_clk(ldb, imx_ldb_ch->chno);
-       if (ret)
-               return ret;
-
-       if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
-               ret = imx_ldb_get_clk(ldb, 1);
-               if (ret)
-                       return ret;
-       }
-
-       drm_encoder_helper_add(&imx_ldb_ch->encoder,
-                       &imx_ldb_encoder_helper_funcs);
-       drm_encoder_init(drm, &imx_ldb_ch->encoder, &imx_ldb_encoder_funcs,
-                        DRM_MODE_ENCODER_LVDS);
-
-       drm_connector_helper_add(&imx_ldb_ch->connector,
-                       &imx_ldb_connector_helper_funcs);
-       drm_connector_init(drm, &imx_ldb_ch->connector,
-                          &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
-
-       drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
-                       &imx_ldb_ch->encoder);
-
-       return 0;
-}
-
-enum {
-       LVDS_BIT_MAP_SPWG,
-       LVDS_BIT_MAP_JEIDA
-};
-
-static const char * const imx_ldb_bit_mappings[] = {
-       [LVDS_BIT_MAP_SPWG]  = "spwg",
-       [LVDS_BIT_MAP_JEIDA] = "jeida",
-};
-
-static const int of_get_data_mapping(struct device_node *np)
-{
-       const char *bm;
-       int ret, i;
-
-       ret = of_property_read_string(np, "fsl,data-mapping", &bm);
-       if (ret < 0)
-               return ret;
-
-       for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++)
-               if (!strcasecmp(bm, imx_ldb_bit_mappings[i]))
-                       return i;
-
-       return -EINVAL;
-}
-
-static struct bus_mux imx6q_lvds_mux[2] = {
-       {
-               .reg = IOMUXC_GPR3,
-               .shift = 6,
-               .mask = IMX6Q_GPR3_LVDS0_MUX_CTL_MASK,
-       }, {
-               .reg = IOMUXC_GPR3,
-               .shift = 8,
-               .mask = IMX6Q_GPR3_LVDS1_MUX_CTL_MASK,
-       }
-};
-
-/*
- * For a device declaring compatible = "fsl,imx6q-ldb", "fsl,imx53-ldb",
- * of_match_device will walk through this list and take the first entry
- * matching any of its compatible values. Therefore, the more generic
- * entries (in this case fsl,imx53-ldb) need to be ordered last.
- */
-static const struct of_device_id imx_ldb_dt_ids[] = {
-       { .compatible = "fsl,imx6q-ldb", .data = imx6q_lvds_mux, },
-       { .compatible = "fsl,imx53-ldb", .data = NULL, },
-       { }
-};
-MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
-
-static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
-{
-       struct drm_device *drm = data;
-       struct device_node *np = dev->of_node;
-       const struct of_device_id *of_id =
-                       of_match_device(imx_ldb_dt_ids, dev);
-       struct device_node *child;
-       const u8 *edidp;
-       struct imx_ldb *imx_ldb;
-       int datawidth;
-       int mapping;
-       int dual;
-       int ret;
-       int i;
-
-       imx_ldb = devm_kzalloc(dev, sizeof(*imx_ldb), GFP_KERNEL);
-       if (!imx_ldb)
-               return -ENOMEM;
-
-       imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
-       if (IS_ERR(imx_ldb->regmap)) {
-               dev_err(dev, "failed to get parent regmap\n");
-               return PTR_ERR(imx_ldb->regmap);
-       }
-
-       imx_ldb->dev = dev;
-
-       if (of_id)
-               imx_ldb->lvds_mux = of_id->data;
-
-       dual = of_property_read_bool(np, "fsl,dual-channel");
-       if (dual)
-               imx_ldb->ldb_ctrl |= LDB_SPLIT_MODE_EN;
-
-       /*
-        * There are three different possible clock mux configurations:
-        * i.MX53:  ipu1_di0_sel, ipu1_di1_sel
-        * i.MX6q:  ipu1_di0_sel, ipu1_di1_sel, ipu2_di0_sel, ipu2_di1_sel
-        * i.MX6dl: ipu1_di0_sel, ipu1_di1_sel, lcdif_sel
-        * Map them all to di0_sel...di3_sel.
-        */
-       for (i = 0; i < 4; i++) {
-               char clkname[16];
-
-               sprintf(clkname, "di%d_sel", i);
-               imx_ldb->clk_sel[i] = devm_clk_get(imx_ldb->dev, clkname);
-               if (IS_ERR(imx_ldb->clk_sel[i])) {
-                       ret = PTR_ERR(imx_ldb->clk_sel[i]);
-                       imx_ldb->clk_sel[i] = NULL;
-                       break;
-               }
-       }
-       if (i == 0)
-               return ret;
-
-       for_each_child_of_node(np, child) {
-               struct imx_ldb_channel *channel;
-
-               ret = of_property_read_u32(child, "reg", &i);
-               if (ret || i < 0 || i > 1)
-                       return -EINVAL;
-
-               if (dual && i > 0) {
-                       dev_warn(dev, "dual-channel mode, ignoring second output\n");
-                       continue;
-               }
-
-               if (!of_device_is_available(child))
-                       continue;
-
-               channel = &imx_ldb->channel[i];
-               channel->ldb = imx_ldb;
-               channel->chno = i;
-               channel->child = child;
-
-               edidp = of_get_property(child, "edid", &channel->edid_len);
-               if (edidp) {
-                       channel->edid = kmemdup(edidp, channel->edid_len,
-                                               GFP_KERNEL);
-               } else {
-                       ret = of_get_drm_display_mode(child, &channel->mode, 0);
-                       if (!ret)
-                               channel->mode_valid = 1;
-               }
-
-               ret = of_property_read_u32(child, "fsl,data-width", &datawidth);
-               if (ret)
-                       datawidth = 0;
-               else if (datawidth != 18 && datawidth != 24)
-                       return -EINVAL;
-
-               mapping = of_get_data_mapping(child);
-               switch (mapping) {
-               case LVDS_BIT_MAP_SPWG:
-                       if (datawidth == 24) {
-                               if (i == 0 || dual)
-                                       imx_ldb->ldb_ctrl |=
-                                               LDB_DATA_WIDTH_CH0_24;
-                               if (i == 1 || dual)
-                                       imx_ldb->ldb_ctrl |=
-                                               LDB_DATA_WIDTH_CH1_24;
-                       }
-                       break;
-               case LVDS_BIT_MAP_JEIDA:
-                       if (datawidth == 18) {
-                               dev_err(dev, "JEIDA standard only supported in 24 bit\n");
-                               return -EINVAL;
-                       }
-                       if (i == 0 || dual)
-                               imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 |
-                                       LDB_BIT_MAP_CH0_JEIDA;
-                       if (i == 1 || dual)
-                               imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 |
-                                       LDB_BIT_MAP_CH1_JEIDA;
-                       break;
-               default:
-                       dev_err(dev, "data mapping not specified or invalid\n");
-                       return -EINVAL;
-               }
-
-               ret = imx_ldb_register(drm, channel);
-               if (ret)
-                       return ret;
-       }
-
-       dev_set_drvdata(dev, imx_ldb);
-
-       return 0;
-}
-
-static void imx_ldb_unbind(struct device *dev, struct device *master,
-       void *data)
-{
-       struct imx_ldb *imx_ldb = dev_get_drvdata(dev);
-       int i;
-
-       for (i = 0; i < 2; i++) {
-               struct imx_ldb_channel *channel = &imx_ldb->channel[i];
-
-               if (!channel->connector.funcs)
-                       continue;
-
-               channel->connector.funcs->destroy(&channel->connector);
-               channel->encoder.funcs->destroy(&channel->encoder);
-       }
-}
-
-static const struct component_ops imx_ldb_ops = {
-       .bind   = imx_ldb_bind,
-       .unbind = imx_ldb_unbind,
-};
-
-static int imx_ldb_probe(struct platform_device *pdev)
-{
-       return component_add(&pdev->dev, &imx_ldb_ops);
-}
-
-static int imx_ldb_remove(struct platform_device *pdev)
-{
-       component_del(&pdev->dev, &imx_ldb_ops);
-       return 0;
-}
-
-static struct platform_driver imx_ldb_driver = {
-       .probe          = imx_ldb_probe,
-       .remove         = imx_ldb_remove,
-       .driver         = {
-               .of_match_table = imx_ldb_dt_ids,
-               .name   = DRIVER_NAME,
-               .owner  = THIS_MODULE,
-       },
-};
-
-module_platform_driver(imx_ldb_driver);
-
-MODULE_DESCRIPTION("i.MX LVDS driver");
-MODULE_AUTHOR("Sascha Hauer, Pengutronix");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
deleted file mode 100644 (file)
index 42c651b..0000000
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * i.MX drm driver - Television Encoder (TVEv2)
- *
- * Copyright (C) 2013 Philipp Zabel, Pengutronix
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
-
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/component.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/regmap.h>
-#include <linux/regulator/consumer.h>
-#include <linux/spinlock.h>
-#include <linux/videodev2.h>
-#include <drm/drmP.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_crtc_helper.h>
-#include <video/imx-ipu-v3.h>
-
-#include "imx-drm.h"
-
-#define TVE_COM_CONF_REG       0x00
-#define TVE_TVDAC0_CONT_REG    0x28
-#define TVE_TVDAC1_CONT_REG    0x2c
-#define TVE_TVDAC2_CONT_REG    0x30
-#define TVE_CD_CONT_REG                0x34
-#define TVE_INT_CONT_REG       0x64
-#define TVE_STAT_REG           0x68
-#define TVE_TST_MODE_REG       0x6c
-#define TVE_MV_CONT_REG                0xdc
-
-/* TVE_COM_CONF_REG */
-#define TVE_SYNC_CH_2_EN       BIT(22)
-#define TVE_SYNC_CH_1_EN       BIT(21)
-#define TVE_SYNC_CH_0_EN       BIT(20)
-#define TVE_TV_OUT_MODE_MASK   (0x7 << 12)
-#define TVE_TV_OUT_DISABLE     (0x0 << 12)
-#define TVE_TV_OUT_CVBS_0      (0x1 << 12)
-#define TVE_TV_OUT_CVBS_2      (0x2 << 12)
-#define TVE_TV_OUT_CVBS_0_2    (0x3 << 12)
-#define TVE_TV_OUT_SVIDEO_0_1  (0x4 << 12)
-#define TVE_TV_OUT_SVIDEO_0_1_CVBS2_2  (0x5 << 12)
-#define TVE_TV_OUT_YPBPR       (0x6 << 12)
-#define TVE_TV_OUT_RGB         (0x7 << 12)
-#define TVE_TV_STAND_MASK      (0xf << 8)
-#define TVE_TV_STAND_HD_1080P30        (0xc << 8)
-#define TVE_P2I_CONV_EN                BIT(7)
-#define TVE_INP_VIDEO_FORM     BIT(6)
-#define TVE_INP_YCBCR_422      (0x0 << 6)
-#define TVE_INP_YCBCR_444      (0x1 << 6)
-#define TVE_DATA_SOURCE_MASK   (0x3 << 4)
-#define TVE_DATA_SOURCE_BUS1   (0x0 << 4)
-#define TVE_DATA_SOURCE_BUS2   (0x1 << 4)
-#define TVE_DATA_SOURCE_EXT    (0x2 << 4)
-#define TVE_DATA_SOURCE_TESTGEN        (0x3 << 4)
-#define TVE_IPU_CLK_EN_OFS     3
-#define TVE_IPU_CLK_EN         BIT(3)
-#define TVE_DAC_SAMP_RATE_OFS  1
-#define TVE_DAC_SAMP_RATE_WIDTH        2
-#define TVE_DAC_SAMP_RATE_MASK (0x3 << 1)
-#define TVE_DAC_FULL_RATE      (0x0 << 1)
-#define TVE_DAC_DIV2_RATE      (0x1 << 1)
-#define TVE_DAC_DIV4_RATE      (0x2 << 1)
-#define TVE_EN                 BIT(0)
-
-/* TVE_TVDACx_CONT_REG */
-#define TVE_TVDAC_GAIN_MASK    (0x3f << 0)
-
-/* TVE_CD_CONT_REG */
-#define TVE_CD_CH_2_SM_EN      BIT(22)
-#define TVE_CD_CH_1_SM_EN      BIT(21)
-#define TVE_CD_CH_0_SM_EN      BIT(20)
-#define TVE_CD_CH_2_LM_EN      BIT(18)
-#define TVE_CD_CH_1_LM_EN      BIT(17)
-#define TVE_CD_CH_0_LM_EN      BIT(16)
-#define TVE_CD_CH_2_REF_LVL    BIT(10)
-#define TVE_CD_CH_1_REF_LVL    BIT(9)
-#define TVE_CD_CH_0_REF_LVL    BIT(8)
-#define TVE_CD_EN              BIT(0)
-
-/* TVE_INT_CONT_REG */
-#define TVE_FRAME_END_IEN      BIT(13)
-#define TVE_CD_MON_END_IEN     BIT(2)
-#define TVE_CD_SM_IEN          BIT(1)
-#define TVE_CD_LM_IEN          BIT(0)
-
-/* TVE_TST_MODE_REG */
-#define TVE_TVDAC_TEST_MODE_MASK       (0x7 << 0)
-
-#define con_to_tve(x) container_of(x, struct imx_tve, connector)
-#define enc_to_tve(x) container_of(x, struct imx_tve, encoder)
-
-enum {
-       TVE_MODE_TVOUT,
-       TVE_MODE_VGA,
-};
-
-struct imx_tve {
-       struct drm_connector connector;
-       struct drm_encoder encoder;
-       struct device *dev;
-       spinlock_t lock;        /* register lock */
-       bool enabled;
-       int mode;
-
-       struct regmap *regmap;
-       struct regulator *dac_reg;
-       struct i2c_adapter *ddc;
-       struct clk *clk;
-       struct clk *di_sel_clk;
-       struct clk_hw clk_hw_di;
-       struct clk *di_clk;
-       int vsync_pin;
-       int hsync_pin;
-};
-
-static void tve_lock(void *__tve)
-__acquires(&tve->lock)
-{
-       struct imx_tve *tve = __tve;
-
-       spin_lock(&tve->lock);
-}
-
-static void tve_unlock(void *__tve)
-__releases(&tve->lock)
-{
-       struct imx_tve *tve = __tve;
-
-       spin_unlock(&tve->lock);
-}
-
-static void tve_enable(struct imx_tve *tve)
-{
-       int ret;
-
-       if (!tve->enabled) {
-               tve->enabled = true;
-               clk_prepare_enable(tve->clk);
-               ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG,
-                                        TVE_IPU_CLK_EN | TVE_EN,
-                                        TVE_IPU_CLK_EN | TVE_EN);
-       }
-
-       /* clear interrupt status register */
-       regmap_write(tve->regmap, TVE_STAT_REG, 0xffffffff);
-
-       /* cable detection irq disabled in VGA mode, enabled in TVOUT mode */
-       if (tve->mode == TVE_MODE_VGA)
-               regmap_write(tve->regmap, TVE_INT_CONT_REG, 0);
-       else
-               regmap_write(tve->regmap, TVE_INT_CONT_REG,
-                            TVE_CD_SM_IEN |
-                            TVE_CD_LM_IEN |
-                            TVE_CD_MON_END_IEN);
-}
-
-static void tve_disable(struct imx_tve *tve)
-{
-       int ret;
-
-       if (tve->enabled) {
-               tve->enabled = false;
-               ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG,
-                                        TVE_IPU_CLK_EN | TVE_EN, 0);
-               clk_disable_unprepare(tve->clk);
-       }
-}
-
-static int tve_setup_tvout(struct imx_tve *tve)
-{
-       return -ENOTSUPP;
-}
-
-static int tve_setup_vga(struct imx_tve *tve)
-{
-       unsigned int mask;
-       unsigned int val;
-       int ret;
-
-       /* set gain to (1 + 10/128) to provide 0.7V peak-to-peak amplitude */
-       ret = regmap_update_bits(tve->regmap, TVE_TVDAC0_CONT_REG,
-                                TVE_TVDAC_GAIN_MASK, 0x0a);
-       ret = regmap_update_bits(tve->regmap, TVE_TVDAC1_CONT_REG,
-                                TVE_TVDAC_GAIN_MASK, 0x0a);
-       ret = regmap_update_bits(tve->regmap, TVE_TVDAC2_CONT_REG,
-                                TVE_TVDAC_GAIN_MASK, 0x0a);
-
-       /* set configuration register */
-       mask = TVE_DATA_SOURCE_MASK | TVE_INP_VIDEO_FORM;
-       val  = TVE_DATA_SOURCE_BUS2 | TVE_INP_YCBCR_444;
-       mask |= TVE_TV_STAND_MASK       | TVE_P2I_CONV_EN;
-       val  |= TVE_TV_STAND_HD_1080P30 | 0;
-       mask |= TVE_TV_OUT_MODE_MASK | TVE_SYNC_CH_0_EN;
-       val  |= TVE_TV_OUT_RGB       | TVE_SYNC_CH_0_EN;
-       ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, mask, val);
-       if (ret < 0) {
-               dev_err(tve->dev, "failed to set configuration: %d\n", ret);
-               return ret;
-       }
-
-       /* set test mode (as documented) */
-       ret = regmap_update_bits(tve->regmap, TVE_TST_MODE_REG,
-                                TVE_TVDAC_TEST_MODE_MASK, 1);
-
-       return 0;
-}
-
-static enum drm_connector_status imx_tve_connector_detect(
-                               struct drm_connector *connector, bool force)
-{
-       return connector_status_connected;
-}
-
-static int imx_tve_connector_get_modes(struct drm_connector *connector)
-{
-       struct imx_tve *tve = con_to_tve(connector);
-       struct edid *edid;
-       int ret = 0;
-
-       if (!tve->ddc)
-               return 0;
-
-       edid = drm_get_edid(connector, tve->ddc);
-       if (edid) {
-               drm_mode_connector_update_edid_property(connector, edid);
-               ret = drm_add_edid_modes(connector, edid);
-               kfree(edid);
-       }
-
-       return ret;
-}
-
-static int imx_tve_connector_mode_valid(struct drm_connector *connector,
-                                       struct drm_display_mode *mode)
-{
-       struct imx_tve *tve = con_to_tve(connector);
-       unsigned long rate;
-
-       /* pixel clock with 2x oversampling */
-       rate = clk_round_rate(tve->clk, 2000UL * mode->clock) / 2000;
-       if (rate == mode->clock)
-               return MODE_OK;
-
-       /* pixel clock without oversampling */
-       rate = clk_round_rate(tve->clk, 1000UL * mode->clock) / 1000;
-       if (rate == mode->clock)
-               return MODE_OK;
-
-       dev_warn(tve->dev, "ignoring mode %dx%d\n",
-                mode->hdisplay, mode->vdisplay);
-
-       return MODE_BAD;
-}
-
-static struct drm_encoder *imx_tve_connector_best_encoder(
-               struct drm_connector *connector)
-{
-       struct imx_tve *tve = con_to_tve(connector);
-
-       return &tve->encoder;
-}
-
-static void imx_tve_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-       struct imx_tve *tve = enc_to_tve(encoder);
-       int ret;
-
-       ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG,
-                                TVE_TV_OUT_MODE_MASK, TVE_TV_OUT_DISABLE);
-       if (ret < 0)
-               dev_err(tve->dev, "failed to disable TVOUT: %d\n", ret);
-}
-
-static bool imx_tve_encoder_mode_fixup(struct drm_encoder *encoder,
-                                      const struct drm_display_mode *mode,
-                                      struct drm_display_mode *adjusted_mode)
-{
-       return true;
-}
-
-static void imx_tve_encoder_prepare(struct drm_encoder *encoder)
-{
-       struct imx_tve *tve = enc_to_tve(encoder);
-
-       tve_disable(tve);
-
-       switch (tve->mode) {
-       case TVE_MODE_VGA:
-               imx_drm_panel_format_pins(encoder, IPU_PIX_FMT_GBR24,
-                               tve->hsync_pin, tve->vsync_pin);
-               break;
-       case TVE_MODE_TVOUT:
-               imx_drm_panel_format(encoder, V4L2_PIX_FMT_YUV444);
-               break;
-       }
-}
-
-static void imx_tve_encoder_mode_set(struct drm_encoder *encoder,
-                                    struct drm_display_mode *mode,
-                                    struct drm_display_mode *adjusted_mode)
-{
-       struct imx_tve *tve = enc_to_tve(encoder);
-       unsigned long rounded_rate;
-       unsigned long rate;
-       int div = 1;
-       int ret;
-
-       /*
-        * FIXME
-        * we should try 4k * mode->clock first,
-        * and enable 4x oversampling for lower resolutions
-        */
-       rate = 2000UL * mode->clock;
-       clk_set_rate(tve->clk, rate);
-       rounded_rate = clk_get_rate(tve->clk);
-       if (rounded_rate >= rate)
-               div = 2;
-       clk_set_rate(tve->di_clk, rounded_rate / div);
-
-       ret = clk_set_parent(tve->di_sel_clk, tve->di_clk);
-       if (ret < 0) {
-               dev_err(tve->dev, "failed to set di_sel parent to tve_di: %d\n",
-                       ret);
-       }
-
-       if (tve->mode == TVE_MODE_VGA)
-               tve_setup_vga(tve);
-       else
-               tve_setup_tvout(tve);
-}
-
-static void imx_tve_encoder_commit(struct drm_encoder *encoder)
-{
-       struct imx_tve *tve = enc_to_tve(encoder);
-
-       tve_enable(tve);
-}
-
-static void imx_tve_encoder_disable(struct drm_encoder *encoder)
-{
-       struct imx_tve *tve = enc_to_tve(encoder);
-
-       tve_disable(tve);
-}
-
-static struct drm_connector_funcs imx_tve_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .detect = imx_tve_connector_detect,
-       .destroy = imx_drm_connector_destroy,
-};
-
-static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
-       .get_modes = imx_tve_connector_get_modes,
-       .best_encoder = imx_tve_connector_best_encoder,
-       .mode_valid = imx_tve_connector_mode_valid,
-};
-
-static struct drm_encoder_funcs imx_tve_encoder_funcs = {
-       .destroy = imx_drm_encoder_destroy,
-};
-
-static struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = {
-       .dpms = imx_tve_encoder_dpms,
-       .mode_fixup = imx_tve_encoder_mode_fixup,
-       .prepare = imx_tve_encoder_prepare,
-       .mode_set = imx_tve_encoder_mode_set,
-       .commit = imx_tve_encoder_commit,
-       .disable = imx_tve_encoder_disable,
-};
-
-static irqreturn_t imx_tve_irq_handler(int irq, void *data)
-{
-       struct imx_tve *tve = data;
-       unsigned int val;
-
-       regmap_read(tve->regmap, TVE_STAT_REG, &val);
-
-       /* clear interrupt status register */
-       regmap_write(tve->regmap, TVE_STAT_REG, 0xffffffff);
-
-       return IRQ_HANDLED;
-}
-
-static unsigned long clk_tve_di_recalc_rate(struct clk_hw *hw,
-                                           unsigned long parent_rate)
-{
-       struct imx_tve *tve = container_of(hw, struct imx_tve, clk_hw_di);
-       unsigned int val;
-       int ret;
-
-       ret = regmap_read(tve->regmap, TVE_COM_CONF_REG, &val);
-       if (ret < 0)
-               return 0;
-
-       switch (val & TVE_DAC_SAMP_RATE_MASK) {
-       case TVE_DAC_DIV4_RATE:
-               return parent_rate / 4;
-       case TVE_DAC_DIV2_RATE:
-               return parent_rate / 2;
-       case TVE_DAC_FULL_RATE:
-       default:
-               return parent_rate;
-       }
-
-       return 0;
-}
-
-static long clk_tve_di_round_rate(struct clk_hw *hw, unsigned long rate,
-                                 unsigned long *prate)
-{
-       unsigned long div;
-
-       div = *prate / rate;
-       if (div >= 4)
-               return *prate / 4;
-       else if (div >= 2)
-               return *prate / 2;
-       return *prate;
-}
-
-static int clk_tve_di_set_rate(struct clk_hw *hw, unsigned long rate,
-                              unsigned long parent_rate)
-{
-       struct imx_tve *tve = container_of(hw, struct imx_tve, clk_hw_di);
-       unsigned long div;
-       u32 val;
-       int ret;
-
-       div = parent_rate / rate;
-       if (div >= 4)
-               val = TVE_DAC_DIV4_RATE;
-       else if (div >= 2)
-               val = TVE_DAC_DIV2_RATE;
-       else
-               val = TVE_DAC_FULL_RATE;
-
-       ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG,
-                                TVE_DAC_SAMP_RATE_MASK, val);
-
-       if (ret < 0) {
-               dev_err(tve->dev, "failed to set divider: %d\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static struct clk_ops clk_tve_di_ops = {
-       .round_rate = clk_tve_di_round_rate,
-       .set_rate = clk_tve_di_set_rate,
-       .recalc_rate = clk_tve_di_recalc_rate,
-};
-
-static int tve_clk_init(struct imx_tve *tve, void __iomem *base)
-{
-       const char *tve_di_parent[1];
-       struct clk_init_data init = {
-               .name = "tve_di",
-               .ops = &clk_tve_di_ops,
-               .num_parents = 1,
-               .flags = 0,
-       };
-
-       tve_di_parent[0] = __clk_get_name(tve->clk);
-       init.parent_names = (const char **)&tve_di_parent;
-
-       tve->clk_hw_di.init = &init;
-       tve->di_clk = clk_register(tve->dev, &tve->clk_hw_di);
-       if (IS_ERR(tve->di_clk)) {
-               dev_err(tve->dev, "failed to register TVE output clock: %ld\n",
-                       PTR_ERR(tve->di_clk));
-               return PTR_ERR(tve->di_clk);
-       }
-
-       return 0;
-}
-
-static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve)
-{
-       int encoder_type;
-       int ret;
-
-       encoder_type = tve->mode == TVE_MODE_VGA ?
-                               DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC;
-
-       ret = imx_drm_encoder_parse_of(drm, &tve->encoder,
-                                      tve->dev->of_node);
-       if (ret)
-               return ret;
-
-       drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs);
-       drm_encoder_init(drm, &tve->encoder, &imx_tve_encoder_funcs,
-                        encoder_type);
-
-       drm_connector_helper_add(&tve->connector,
-                       &imx_tve_connector_helper_funcs);
-       drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs,
-                          DRM_MODE_CONNECTOR_VGA);
-
-       drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder);
-
-       return 0;
-}
-
-static bool imx_tve_readable_reg(struct device *dev, unsigned int reg)
-{
-       return (reg % 4 == 0) && (reg <= 0xdc);
-}
-
-static struct regmap_config tve_regmap_config = {
-       .reg_bits = 32,
-       .val_bits = 32,
-       .reg_stride = 4,
-
-       .readable_reg = imx_tve_readable_reg,
-
-       .lock = tve_lock,
-       .unlock = tve_unlock,
-
-       .max_register = 0xdc,
-};
-
-static const char * const imx_tve_modes[] = {
-       [TVE_MODE_TVOUT]  = "tvout",
-       [TVE_MODE_VGA] = "vga",
-};
-
-static const int of_get_tve_mode(struct device_node *np)
-{
-       const char *bm;
-       int ret, i;
-
-       ret = of_property_read_string(np, "fsl,tve-mode", &bm);
-       if (ret < 0)
-               return ret;
-
-       for (i = 0; i < ARRAY_SIZE(imx_tve_modes); i++)
-               if (!strcasecmp(bm, imx_tve_modes[i]))
-                       return i;
-
-       return -EINVAL;
-}
-
-static int imx_tve_bind(struct device *dev, struct device *master, void *data)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct drm_device *drm = data;
-       struct device_node *np = dev->of_node;
-       struct device_node *ddc_node;
-       struct imx_tve *tve;
-       struct resource *res;
-       void __iomem *base;
-       unsigned int val;
-       int irq;
-       int ret;
-
-       tve = devm_kzalloc(dev, sizeof(*tve), GFP_KERNEL);
-       if (!tve)
-               return -ENOMEM;
-
-       tve->dev = dev;
-       spin_lock_init(&tve->lock);
-
-       ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
-       if (ddc_node) {
-               tve->ddc = of_find_i2c_adapter_by_node(ddc_node);
-               of_node_put(ddc_node);
-       }
-
-       tve->mode = of_get_tve_mode(np);
-       if (tve->mode != TVE_MODE_VGA) {
-               dev_err(dev, "only VGA mode supported, currently\n");
-               return -EINVAL;
-       }
-
-       if (tve->mode == TVE_MODE_VGA) {
-               ret = of_property_read_u32(np, "fsl,hsync-pin",
-                                          &tve->hsync_pin);
-
-               if (ret < 0) {
-                       dev_err(dev, "failed to get vsync pin\n");
-                       return ret;
-               }
-
-               ret |= of_property_read_u32(np, "fsl,vsync-pin",
-                                           &tve->vsync_pin);
-
-               if (ret < 0) {
-                       dev_err(dev, "failed to get vsync pin\n");
-                       return ret;
-               }
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(base))
-               return PTR_ERR(base);
-
-       tve_regmap_config.lock_arg = tve;
-       tve->regmap = devm_regmap_init_mmio_clk(dev, "tve", base,
-                                               &tve_regmap_config);
-       if (IS_ERR(tve->regmap)) {
-               dev_err(dev, "failed to init regmap: %ld\n",
-                       PTR_ERR(tve->regmap));
-               return PTR_ERR(tve->regmap);
-       }
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(dev, "failed to get irq\n");
-               return irq;
-       }
-
-       ret = devm_request_threaded_irq(dev, irq, NULL,
-                                       imx_tve_irq_handler, IRQF_ONESHOT,
-                                       "imx-tve", tve);
-       if (ret < 0) {
-               dev_err(dev, "failed to request irq: %d\n", ret);
-               return ret;
-       }
-
-       tve->dac_reg = devm_regulator_get(dev, "dac");
-       if (!IS_ERR(tve->dac_reg)) {
-               regulator_set_voltage(tve->dac_reg, 2750000, 2750000);
-               ret = regulator_enable(tve->dac_reg);
-               if (ret)
-                       return ret;
-       }
-
-       tve->clk = devm_clk_get(dev, "tve");
-       if (IS_ERR(tve->clk)) {
-               dev_err(dev, "failed to get high speed tve clock: %ld\n",
-                       PTR_ERR(tve->clk));
-               return PTR_ERR(tve->clk);
-       }
-
-       /* this is the IPU DI clock input selector, can be parented to tve_di */
-       tve->di_sel_clk = devm_clk_get(dev, "di_sel");
-       if (IS_ERR(tve->di_sel_clk)) {
-               dev_err(dev, "failed to get ipu di mux clock: %ld\n",
-                       PTR_ERR(tve->di_sel_clk));
-               return PTR_ERR(tve->di_sel_clk);
-       }
-
-       ret = tve_clk_init(tve, base);
-       if (ret < 0)
-               return ret;
-
-       ret = regmap_read(tve->regmap, TVE_COM_CONF_REG, &val);
-       if (ret < 0) {
-               dev_err(dev, "failed to read configuration register: %d\n", ret);
-               return ret;
-       }
-       if (val != 0x00100000) {
-               dev_err(dev, "configuration register default value indicates this is not a TVEv2\n");
-               return -ENODEV;
-       }
-
-       /* disable cable detection for VGA mode */
-       ret = regmap_write(tve->regmap, TVE_CD_CONT_REG, 0);
-
-       ret = imx_tve_register(drm, tve);
-       if (ret)
-               return ret;
-
-       dev_set_drvdata(dev, tve);
-
-       return 0;
-}
-
-static void imx_tve_unbind(struct device *dev, struct device *master,
-       void *data)
-{
-       struct imx_tve *tve = dev_get_drvdata(dev);
-
-       tve->connector.funcs->destroy(&tve->connector);
-       tve->encoder.funcs->destroy(&tve->encoder);
-
-       if (!IS_ERR(tve->dac_reg))
-               regulator_disable(tve->dac_reg);
-}
-
-static const struct component_ops imx_tve_ops = {
-       .bind   = imx_tve_bind,
-       .unbind = imx_tve_unbind,
-};
-
-static int imx_tve_probe(struct platform_device *pdev)
-{
-       return component_add(&pdev->dev, &imx_tve_ops);
-}
-
-static int imx_tve_remove(struct platform_device *pdev)
-{
-       component_del(&pdev->dev, &imx_tve_ops);
-       return 0;
-}
-
-static const struct of_device_id imx_tve_dt_ids[] = {
-       { .compatible = "fsl,imx53-tve", },
-       { /* sentinel */ }
-};
-
-static struct platform_driver imx_tve_driver = {
-       .probe          = imx_tve_probe,
-       .remove         = imx_tve_remove,
-       .driver         = {
-               .of_match_table = imx_tve_dt_ids,
-               .name   = "imx-tve",
-               .owner  = THIS_MODULE,
-       },
-};
-
-module_platform_driver(imx_tve_driver);
-
-MODULE_DESCRIPTION("i.MX Television Encoder driver");
-MODULE_AUTHOR("Philipp Zabel, Pengutronix");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-tve");
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
deleted file mode 100644 (file)
index 11e84a2..0000000
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * i.MX IPUv3 Graphics driver
- *
- * Copyright (C) 2011 Sascha Hauer, Pengutronix
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
-#include <linux/component.h>
-#include <linux/module.h>
-#include <linux/export.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
-#include <linux/fb.h>
-#include <linux/clk.h>
-#include <linux/errno.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-
-#include <video/imx-ipu-v3.h>
-#include "imx-drm.h"
-#include "ipuv3-plane.h"
-
-#define DRIVER_DESC            "i.MX IPUv3 Graphics"
-
-struct ipu_crtc {
-       struct device           *dev;
-       struct drm_crtc         base;
-       struct imx_drm_crtc     *imx_crtc;
-
-       /* plane[0] is the full plane, plane[1] is the partial plane */
-       struct ipu_plane        *plane[2];
-
-       struct ipu_dc           *dc;
-       struct ipu_di           *di;
-       int                     enabled;
-       struct drm_pending_vblank_event *page_flip_event;
-       struct drm_framebuffer  *newfb;
-       int                     irq;
-       u32                     interface_pix_fmt;
-       unsigned long           di_clkflags;
-       int                     di_hsync_pin;
-       int                     di_vsync_pin;
-};
-
-#define to_ipu_crtc(x) container_of(x, struct ipu_crtc, base)
-
-static void ipu_fb_enable(struct ipu_crtc *ipu_crtc)
-{
-       struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
-
-       if (ipu_crtc->enabled)
-               return;
-
-       ipu_dc_enable(ipu);
-       ipu_plane_enable(ipu_crtc->plane[0]);
-       /* Start DC channel and DI after IDMAC */
-       ipu_dc_enable_channel(ipu_crtc->dc);
-       ipu_di_enable(ipu_crtc->di);
-
-       ipu_crtc->enabled = 1;
-}
-
-static void ipu_fb_disable(struct ipu_crtc *ipu_crtc)
-{
-       struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
-
-       if (!ipu_crtc->enabled)
-               return;
-
-       /* Stop DC channel and DI before IDMAC */
-       ipu_dc_disable_channel(ipu_crtc->dc);
-       ipu_di_disable(ipu_crtc->di);
-       ipu_plane_disable(ipu_crtc->plane[0]);
-       ipu_dc_disable(ipu);
-
-       ipu_crtc->enabled = 0;
-}
-
-static void ipu_crtc_dpms(struct drm_crtc *crtc, int mode)
-{
-       struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
-
-       dev_dbg(ipu_crtc->dev, "%s mode: %d\n", __func__, mode);
-
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-               ipu_fb_enable(ipu_crtc);
-               break;
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-       case DRM_MODE_DPMS_OFF:
-               ipu_fb_disable(ipu_crtc);
-               break;
-       }
-}
-
-static int ipu_page_flip(struct drm_crtc *crtc,
-               struct drm_framebuffer *fb,
-               struct drm_pending_vblank_event *event,
-               uint32_t page_flip_flags)
-{
-       struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
-       int ret;
-
-       if (ipu_crtc->newfb)
-               return -EBUSY;
-
-       ret = imx_drm_crtc_vblank_get(ipu_crtc->imx_crtc);
-       if (ret) {
-               dev_dbg(ipu_crtc->dev, "failed to acquire vblank counter\n");
-               list_del(&event->base.link);
-
-               return ret;
-       }
-
-       ipu_crtc->newfb = fb;
-       ipu_crtc->page_flip_event = event;
-       crtc->primary->fb = fb;
-
-       return 0;
-}
-
-static const struct drm_crtc_funcs ipu_crtc_funcs = {
-       .set_config = drm_crtc_helper_set_config,
-       .destroy = drm_crtc_cleanup,
-       .page_flip = ipu_page_flip,
-};
-
-static int ipu_crtc_mode_set(struct drm_crtc *crtc,
-                              struct drm_display_mode *orig_mode,
-                              struct drm_display_mode *mode,
-                              int x, int y,
-                              struct drm_framebuffer *old_fb)
-{
-       struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
-       int ret;
-       struct ipu_di_signal_cfg sig_cfg = {};
-       u32 out_pixel_fmt;
-
-       dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__,
-                       mode->hdisplay);
-       dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__,
-                       mode->vdisplay);
-
-       out_pixel_fmt = ipu_crtc->interface_pix_fmt;
-
-       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-               sig_cfg.interlaced = 1;
-       if (mode->flags & DRM_MODE_FLAG_PHSYNC)
-               sig_cfg.Hsync_pol = 1;
-       if (mode->flags & DRM_MODE_FLAG_PVSYNC)
-               sig_cfg.Vsync_pol = 1;
-
-       sig_cfg.enable_pol = 1;
-       sig_cfg.clk_pol = 0;
-       sig_cfg.width = mode->hdisplay;
-       sig_cfg.height = mode->vdisplay;
-       sig_cfg.pixel_fmt = out_pixel_fmt;
-       sig_cfg.h_start_width = mode->htotal - mode->hsync_end;
-       sig_cfg.h_sync_width = mode->hsync_end - mode->hsync_start;
-       sig_cfg.h_end_width = mode->hsync_start - mode->hdisplay;
-
-       sig_cfg.v_start_width = mode->vtotal - mode->vsync_end;
-       sig_cfg.v_sync_width = mode->vsync_end - mode->vsync_start;
-       sig_cfg.v_end_width = mode->vsync_start - mode->vdisplay;
-       sig_cfg.pixelclock = mode->clock * 1000;
-       sig_cfg.clkflags = ipu_crtc->di_clkflags;
-
-       sig_cfg.v_to_h_sync = 0;
-
-       sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin;
-       sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin;
-
-       ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, sig_cfg.interlaced,
-                       out_pixel_fmt, mode->hdisplay);
-       if (ret) {
-               dev_err(ipu_crtc->dev,
-                               "initializing display controller failed with %d\n",
-                               ret);
-               return ret;
-       }
-
-       ret = ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg);
-       if (ret) {
-               dev_err(ipu_crtc->dev,
-                               "initializing panel failed with %d\n", ret);
-               return ret;
-       }
-
-       return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode,
-                                 crtc->primary->fb,
-                                 0, 0, mode->hdisplay, mode->vdisplay,
-                                 x, y, mode->hdisplay, mode->vdisplay);
-}
-
-static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc)
-{
-       unsigned long flags;
-       struct drm_device *drm = ipu_crtc->base.dev;
-
-       spin_lock_irqsave(&drm->event_lock, flags);
-       if (ipu_crtc->page_flip_event)
-               drm_send_vblank_event(drm, -1, ipu_crtc->page_flip_event);
-       ipu_crtc->page_flip_event = NULL;
-       imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc);
-       spin_unlock_irqrestore(&drm->event_lock, flags);
-}
-
-static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
-{
-       struct ipu_crtc *ipu_crtc = dev_id;
-
-       imx_drm_handle_vblank(ipu_crtc->imx_crtc);
-
-       if (ipu_crtc->newfb) {
-               struct ipu_plane *plane = ipu_crtc->plane[0];
-
-               ipu_crtc->newfb = NULL;
-               ipu_plane_set_base(plane, ipu_crtc->base.primary->fb,
-                                  plane->x, plane->y);
-               ipu_crtc_handle_pageflip(ipu_crtc);
-       }
-
-       return IRQ_HANDLED;
-}
-
-static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc,
-                                 const struct drm_display_mode *mode,
-                                 struct drm_display_mode *adjusted_mode)
-{
-       return true;
-}
-
-static void ipu_crtc_prepare(struct drm_crtc *crtc)
-{
-       struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
-
-       ipu_fb_disable(ipu_crtc);
-}
-
-static void ipu_crtc_commit(struct drm_crtc *crtc)
-{
-       struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
-
-       ipu_fb_enable(ipu_crtc);
-}
-
-static struct drm_crtc_helper_funcs ipu_helper_funcs = {
-       .dpms = ipu_crtc_dpms,
-       .mode_fixup = ipu_crtc_mode_fixup,
-       .mode_set = ipu_crtc_mode_set,
-       .prepare = ipu_crtc_prepare,
-       .commit = ipu_crtc_commit,
-};
-
-static int ipu_enable_vblank(struct drm_crtc *crtc)
-{
-       return 0;
-}
-
-static void ipu_disable_vblank(struct drm_crtc *crtc)
-{
-       struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
-
-       ipu_crtc->page_flip_event = NULL;
-       ipu_crtc->newfb = NULL;
-}
-
-static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
-               u32 pixfmt, int hsync_pin, int vsync_pin)
-{
-       struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
-
-       ipu_crtc->interface_pix_fmt = pixfmt;
-       ipu_crtc->di_hsync_pin = hsync_pin;
-       ipu_crtc->di_vsync_pin = vsync_pin;
-
-       switch (encoder_type) {
-       case DRM_MODE_ENCODER_DAC:
-       case DRM_MODE_ENCODER_TVDAC:
-       case DRM_MODE_ENCODER_LVDS:
-               ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC |
-                       IPU_DI_CLKMODE_EXT;
-               break;
-       case DRM_MODE_ENCODER_TMDS:
-       case DRM_MODE_ENCODER_NONE:
-               ipu_crtc->di_clkflags = 0;
-               break;
-       }
-
-       return 0;
-}
-
-static const struct imx_drm_crtc_helper_funcs ipu_crtc_helper_funcs = {
-       .enable_vblank = ipu_enable_vblank,
-       .disable_vblank = ipu_disable_vblank,
-       .set_interface_pix_fmt = ipu_set_interface_pix_fmt,
-       .crtc_funcs = &ipu_crtc_funcs,
-       .crtc_helper_funcs = &ipu_helper_funcs,
-};
-
-static void ipu_put_resources(struct ipu_crtc *ipu_crtc)
-{
-       if (!IS_ERR_OR_NULL(ipu_crtc->dc))
-               ipu_dc_put(ipu_crtc->dc);
-       if (!IS_ERR_OR_NULL(ipu_crtc->di))
-               ipu_di_put(ipu_crtc->di);
-}
-
-static int ipu_get_resources(struct ipu_crtc *ipu_crtc,
-               struct ipu_client_platformdata *pdata)
-{
-       struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
-       int ret;
-
-       ipu_crtc->dc = ipu_dc_get(ipu, pdata->dc);
-       if (IS_ERR(ipu_crtc->dc)) {
-               ret = PTR_ERR(ipu_crtc->dc);
-               goto err_out;
-       }
-
-       ipu_crtc->di = ipu_di_get(ipu, pdata->di);
-       if (IS_ERR(ipu_crtc->di)) {
-               ret = PTR_ERR(ipu_crtc->di);
-               goto err_out;
-       }
-
-       return 0;
-err_out:
-       ipu_put_resources(ipu_crtc);
-
-       return ret;
-}
-
-static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
-       struct ipu_client_platformdata *pdata, struct drm_device *drm)
-{
-       struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
-       int dp = -EINVAL;
-       int ret;
-       int id;
-
-       ret = ipu_get_resources(ipu_crtc, pdata);
-       if (ret) {
-               dev_err(ipu_crtc->dev, "getting resources failed with %d.\n",
-                               ret);
-               return ret;
-       }
-
-       ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc,
-                       &ipu_crtc_helper_funcs, ipu_crtc->dev->of_node);
-       if (ret) {
-               dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
-               goto err_put_resources;
-       }
-
-       if (pdata->dp >= 0)
-               dp = IPU_DP_FLOW_SYNC_BG;
-       id = imx_drm_crtc_id(ipu_crtc->imx_crtc);
-       ipu_crtc->plane[0] = ipu_plane_init(ipu_crtc->base.dev, ipu,
-                                           pdata->dma[0], dp, BIT(id), true);
-       ret = ipu_plane_get_resources(ipu_crtc->plane[0]);
-       if (ret) {
-               dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n",
-                       ret);
-               goto err_remove_crtc;
-       }
-
-       /* If this crtc is using the DP, add an overlay plane */
-       if (pdata->dp >= 0 && pdata->dma[1] > 0) {
-               ipu_crtc->plane[1] = ipu_plane_init(ipu_crtc->base.dev, ipu,
-                                                   pdata->dma[1],
-                                                   IPU_DP_FLOW_SYNC_FG,
-                                                   BIT(id), false);
-               if (IS_ERR(ipu_crtc->plane[1]))
-                       ipu_crtc->plane[1] = NULL;
-       }
-
-       ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]);
-       ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, 0,
-                       "imx_drm", ipu_crtc);
-       if (ret < 0) {
-               dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret);
-               goto err_put_plane_res;
-       }
-
-       return 0;
-
-err_put_plane_res:
-       ipu_plane_put_resources(ipu_crtc->plane[0]);
-err_remove_crtc:
-       imx_drm_remove_crtc(ipu_crtc->imx_crtc);
-err_put_resources:
-       ipu_put_resources(ipu_crtc);
-
-       return ret;
-}
-
-static struct device_node *ipu_drm_get_port_by_id(struct device_node *parent,
-                                                 int port_id)
-{
-       struct device_node *port;
-       int id, ret;
-
-       port = of_get_child_by_name(parent, "port");
-       while (port) {
-               ret = of_property_read_u32(port, "reg", &id);
-               if (!ret && id == port_id)
-                       return port;
-
-               do {
-                       port = of_get_next_child(parent, port);
-                       if (!port)
-                               return NULL;
-               } while (of_node_cmp(port->name, "port"));
-       }
-
-       return NULL;
-}
-
-static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
-{
-       struct ipu_client_platformdata *pdata = dev->platform_data;
-       struct drm_device *drm = data;
-       struct ipu_crtc *ipu_crtc;
-       int ret;
-
-       ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL);
-       if (!ipu_crtc)
-               return -ENOMEM;
-
-       ipu_crtc->dev = dev;
-
-       ret = ipu_crtc_init(ipu_crtc, pdata, drm);
-       if (ret)
-               return ret;
-
-       dev_set_drvdata(dev, ipu_crtc);
-
-       return 0;
-}
-
-static void ipu_drm_unbind(struct device *dev, struct device *master,
-       void *data)
-{
-       struct ipu_crtc *ipu_crtc = dev_get_drvdata(dev);
-
-       imx_drm_remove_crtc(ipu_crtc->imx_crtc);
-
-       ipu_plane_put_resources(ipu_crtc->plane[0]);
-       ipu_put_resources(ipu_crtc);
-}
-
-static const struct component_ops ipu_crtc_ops = {
-       .bind = ipu_drm_bind,
-       .unbind = ipu_drm_unbind,
-};
-
-static int ipu_drm_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct ipu_client_platformdata *pdata = dev->platform_data;
-       int ret;
-
-       if (!dev->platform_data)
-               return -EINVAL;
-
-       if (!dev->of_node) {
-               /* Associate crtc device with the corresponding DI port node */
-               dev->of_node = ipu_drm_get_port_by_id(dev->parent->of_node,
-                                                     pdata->di + 2);
-               if (!dev->of_node) {
-                       dev_err(dev, "missing port@%d node in %s\n",
-                               pdata->di + 2, dev->parent->of_node->full_name);
-                       return -ENODEV;
-               }
-       }
-
-       ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
-       if (ret)
-               return ret;
-
-       return component_add(dev, &ipu_crtc_ops);
-}
-
-static int ipu_drm_remove(struct platform_device *pdev)
-{
-       component_del(&pdev->dev, &ipu_crtc_ops);
-       return 0;
-}
-
-static struct platform_driver ipu_drm_driver = {
-       .driver = {
-               .name = "imx-ipuv3-crtc",
-       },
-       .probe = ipu_drm_probe,
-       .remove = ipu_drm_remove,
-};
-module_platform_driver(ipu_drm_driver);
-
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-ipuv3-crtc");
diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c
deleted file mode 100644 (file)
index 944962b..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * i.MX IPUv3 DP Overlay Planes
- *
- * Copyright (C) 2013 Philipp Zabel, Pengutronix
- *
- * 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 <drm/drmP.h>
-#include <drm/drm_fb_cma_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-
-#include "video/imx-ipu-v3.h"
-#include "ipuv3-plane.h"
-
-#define to_ipu_plane(x)        container_of(x, struct ipu_plane, base)
-
-static const uint32_t ipu_plane_formats[] = {
-       DRM_FORMAT_XRGB1555,
-       DRM_FORMAT_XBGR1555,
-       DRM_FORMAT_ARGB8888,
-       DRM_FORMAT_XRGB8888,
-       DRM_FORMAT_ABGR8888,
-       DRM_FORMAT_XBGR8888,
-       DRM_FORMAT_YUYV,
-       DRM_FORMAT_YVYU,
-       DRM_FORMAT_YUV420,
-       DRM_FORMAT_YVU420,
-};
-
-int ipu_plane_irq(struct ipu_plane *ipu_plane)
-{
-       return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch,
-                                    IPU_IRQ_EOF);
-}
-
-static int calc_vref(struct drm_display_mode *mode)
-{
-       unsigned long htotal, vtotal;
-
-       htotal = mode->htotal;
-       vtotal = mode->vtotal;
-
-       if (!htotal || !vtotal)
-               return 60;
-
-       return DIV_ROUND_UP(mode->clock * 1000, vtotal * htotal);
-}
-
-static inline int calc_bandwidth(int width, int height, unsigned int vref)
-{
-       return width * height * vref;
-}
-
-int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
-                      int x, int y)
-{
-       struct drm_gem_cma_object *cma_obj;
-       unsigned long eba;
-
-       cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
-       if (!cma_obj) {
-               DRM_DEBUG_KMS("entry is null.\n");
-               return -EFAULT;
-       }
-
-       dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
-               &cma_obj->paddr, x, y);
-
-       ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
-
-       eba = cma_obj->paddr + fb->offsets[0] +
-             fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x;
-       ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
-       ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
-
-       /* cache offsets for subsequent pageflips */
-       ipu_plane->x = x;
-       ipu_plane->y = y;
-
-       return 0;
-}
-
-int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
-                      struct drm_display_mode *mode,
-                      struct drm_framebuffer *fb, int crtc_x, int crtc_y,
-                      unsigned int crtc_w, unsigned int crtc_h,
-                      uint32_t src_x, uint32_t src_y,
-                      uint32_t src_w, uint32_t src_h)
-{
-       struct device *dev = ipu_plane->base.dev->dev;
-       int ret;
-
-       /* no scaling */
-       if (src_w != crtc_w || src_h != crtc_h)
-               return -EINVAL;
-
-       /* clip to crtc bounds */
-       if (crtc_x < 0) {
-               if (-crtc_x > crtc_w)
-                       return -EINVAL;
-               src_x += -crtc_x;
-               src_w -= -crtc_x;
-               crtc_w -= -crtc_x;
-               crtc_x = 0;
-       }
-       if (crtc_y < 0) {
-               if (-crtc_y > crtc_h)
-                       return -EINVAL;
-               src_y += -crtc_y;
-               src_h -= -crtc_y;
-               crtc_h -= -crtc_y;
-               crtc_y = 0;
-       }
-       if (crtc_x + crtc_w > mode->hdisplay) {
-               if (crtc_x > mode->hdisplay)
-                       return -EINVAL;
-               crtc_w = mode->hdisplay - crtc_x;
-               src_w = crtc_w;
-       }
-       if (crtc_y + crtc_h > mode->vdisplay) {
-               if (crtc_y > mode->vdisplay)
-                       return -EINVAL;
-               crtc_h = mode->vdisplay - crtc_y;
-               src_h = crtc_h;
-       }
-       /* full plane minimum width is 13 pixels */
-       if (crtc_w < 13 && (ipu_plane->dp_flow != IPU_DP_FLOW_SYNC_FG))
-               return -EINVAL;
-       if (crtc_h < 2)
-               return -EINVAL;
-
-       switch (ipu_plane->dp_flow) {
-       case IPU_DP_FLOW_SYNC_BG:
-               ret = ipu_dp_setup_channel(ipu_plane->dp,
-                               IPUV3_COLORSPACE_RGB,
-                               IPUV3_COLORSPACE_RGB);
-               if (ret) {
-                       dev_err(dev,
-                               "initializing display processor failed with %d\n",
-                               ret);
-                       return ret;
-               }
-               ipu_dp_set_global_alpha(ipu_plane->dp, 1, 0, 1);
-               break;
-       case IPU_DP_FLOW_SYNC_FG:
-               ipu_dp_setup_channel(ipu_plane->dp,
-                               ipu_drm_fourcc_to_colorspace(fb->pixel_format),
-                               IPUV3_COLORSPACE_UNKNOWN);
-               ipu_dp_set_window_pos(ipu_plane->dp, crtc_x, crtc_y);
-               break;
-       }
-
-       ret = ipu_dmfc_init_channel(ipu_plane->dmfc, crtc_w);
-       if (ret) {
-               dev_err(dev, "initializing dmfc channel failed with %d\n", ret);
-               return ret;
-       }
-
-       ret = ipu_dmfc_alloc_bandwidth(ipu_plane->dmfc,
-                       calc_bandwidth(crtc_w, crtc_h,
-                                      calc_vref(mode)), 64);
-       if (ret) {
-               dev_err(dev, "allocating dmfc bandwidth failed with %d\n", ret);
-               return ret;
-       }
-
-       ipu_cpmem_zero(ipu_plane->ipu_ch);
-       ipu_cpmem_set_resolution(ipu_plane->ipu_ch, src_w, src_h);
-       ret = ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->pixel_format);
-       if (ret < 0) {
-               dev_err(dev, "unsupported pixel format 0x%08x\n",
-                       fb->pixel_format);
-               return ret;
-       }
-       ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
-
-       ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
-{
-       if (!IS_ERR_OR_NULL(ipu_plane->dp))
-               ipu_dp_put(ipu_plane->dp);
-       if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
-               ipu_dmfc_put(ipu_plane->dmfc);
-       if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch))
-               ipu_idmac_put(ipu_plane->ipu_ch);
-}
-
-int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
-{
-       int ret;
-
-       ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma);
-       if (IS_ERR(ipu_plane->ipu_ch)) {
-               ret = PTR_ERR(ipu_plane->ipu_ch);
-               DRM_ERROR("failed to get idmac channel: %d\n", ret);
-               return ret;
-       }
-
-       ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma);
-       if (IS_ERR(ipu_plane->dmfc)) {
-               ret = PTR_ERR(ipu_plane->dmfc);
-               DRM_ERROR("failed to get dmfc: ret %d\n", ret);
-               goto err_out;
-       }
-
-       if (ipu_plane->dp_flow >= 0) {
-               ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow);
-               if (IS_ERR(ipu_plane->dp)) {
-                       ret = PTR_ERR(ipu_plane->dp);
-                       DRM_ERROR("failed to get dp flow: %d\n", ret);
-                       goto err_out;
-               }
-       }
-
-       return 0;
-err_out:
-       ipu_plane_put_resources(ipu_plane);
-
-       return ret;
-}
-
-void ipu_plane_enable(struct ipu_plane *ipu_plane)
-{
-       if (ipu_plane->dp)
-               ipu_dp_enable(ipu_plane->ipu);
-       ipu_dmfc_enable_channel(ipu_plane->dmfc);
-       ipu_idmac_enable_channel(ipu_plane->ipu_ch);
-       if (ipu_plane->dp)
-               ipu_dp_enable_channel(ipu_plane->dp);
-
-       ipu_plane->enabled = true;
-}
-
-void ipu_plane_disable(struct ipu_plane *ipu_plane)
-{
-       ipu_plane->enabled = false;
-
-       ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
-
-       if (ipu_plane->dp)
-               ipu_dp_disable_channel(ipu_plane->dp);
-       ipu_idmac_disable_channel(ipu_plane->ipu_ch);
-       ipu_dmfc_disable_channel(ipu_plane->dmfc);
-       if (ipu_plane->dp)
-               ipu_dp_disable(ipu_plane->ipu);
-}
-
-/*
- * drm_plane API
- */
-
-static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
-                           struct drm_framebuffer *fb, int crtc_x, int crtc_y,
-                           unsigned int crtc_w, unsigned int crtc_h,
-                           uint32_t src_x, uint32_t src_y,
-                           uint32_t src_w, uint32_t src_h)
-{
-       struct ipu_plane *ipu_plane = to_ipu_plane(plane);
-       int ret = 0;
-
-       DRM_DEBUG_KMS("plane - %p\n", plane);
-
-       if (!ipu_plane->enabled)
-               ret = ipu_plane_get_resources(ipu_plane);
-       if (ret < 0)
-               return ret;
-
-       ret = ipu_plane_mode_set(ipu_plane, crtc, &crtc->hwmode, fb,
-                       crtc_x, crtc_y, crtc_w, crtc_h,
-                       src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16);
-       if (ret < 0) {
-               ipu_plane_put_resources(ipu_plane);
-               return ret;
-       }
-
-       if (crtc != plane->crtc)
-               dev_info(plane->dev->dev, "crtc change: %p -> %p\n",
-                               plane->crtc, crtc);
-       plane->crtc = crtc;
-
-       if (!ipu_plane->enabled)
-               ipu_plane_enable(ipu_plane);
-
-       return 0;
-}
-
-static int ipu_disable_plane(struct drm_plane *plane)
-{
-       struct ipu_plane *ipu_plane = to_ipu_plane(plane);
-
-       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
-       if (ipu_plane->enabled)
-               ipu_plane_disable(ipu_plane);
-
-       ipu_plane_put_resources(ipu_plane);
-
-       return 0;
-}
-
-static void ipu_plane_destroy(struct drm_plane *plane)
-{
-       struct ipu_plane *ipu_plane = to_ipu_plane(plane);
-
-       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
-       ipu_disable_plane(plane);
-       drm_plane_cleanup(plane);
-       kfree(ipu_plane);
-}
-
-static struct drm_plane_funcs ipu_plane_funcs = {
-       .update_plane   = ipu_update_plane,
-       .disable_plane  = ipu_disable_plane,
-       .destroy        = ipu_plane_destroy,
-};
-
-struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
-                                int dma, int dp, unsigned int possible_crtcs,
-                                bool priv)
-{
-       struct ipu_plane *ipu_plane;
-       int ret;
-
-       DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
-                     dma, dp, possible_crtcs);
-
-       ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL);
-       if (!ipu_plane) {
-               DRM_ERROR("failed to allocate plane\n");
-               return ERR_PTR(-ENOMEM);
-       }
-
-       ipu_plane->ipu = ipu;
-       ipu_plane->dma = dma;
-       ipu_plane->dp_flow = dp;
-
-       ret = drm_plane_init(dev, &ipu_plane->base, possible_crtcs,
-                            &ipu_plane_funcs, ipu_plane_formats,
-                            ARRAY_SIZE(ipu_plane_formats),
-                            priv);
-       if (ret) {
-               DRM_ERROR("failed to initialize plane\n");
-               kfree(ipu_plane);
-               return ERR_PTR(ret);
-       }
-
-       return ipu_plane;
-}
diff --git a/drivers/staging/imx-drm/ipuv3-plane.h b/drivers/staging/imx-drm/ipuv3-plane.h
deleted file mode 100644 (file)
index c0aae5b..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef __IPUV3_PLANE_H__
-#define __IPUV3_PLANE_H__
-
-#include <drm/drm_crtc.h> /* drm_plane */
-
-struct drm_plane;
-struct drm_device;
-struct ipu_soc;
-struct drm_crtc;
-struct drm_framebuffer;
-
-struct ipuv3_channel;
-struct dmfc_channel;
-struct ipu_dp;
-
-struct ipu_plane {
-       struct drm_plane        base;
-
-       struct ipu_soc          *ipu;
-       struct ipuv3_channel    *ipu_ch;
-       struct dmfc_channel     *dmfc;
-       struct ipu_dp           *dp;
-
-       int                     dma;
-       int                     dp_flow;
-
-       int                     x;
-       int                     y;
-
-       bool                    enabled;
-};
-
-struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
-                                int dma, int dp, unsigned int possible_crtcs,
-                                bool priv);
-
-/* Init IDMAC, DMFC, DP */
-int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc,
-                      struct drm_display_mode *mode,
-                      struct drm_framebuffer *fb, int crtc_x, int crtc_y,
-                      unsigned int crtc_w, unsigned int crtc_h,
-                      uint32_t src_x, uint32_t src_y, uint32_t src_w,
-                      uint32_t src_h);
-
-void ipu_plane_enable(struct ipu_plane *plane);
-void ipu_plane_disable(struct ipu_plane *plane);
-int ipu_plane_set_base(struct ipu_plane *plane, struct drm_framebuffer *fb,
-                      int x, int y);
-
-int ipu_plane_get_resources(struct ipu_plane *plane);
-void ipu_plane_put_resources(struct ipu_plane *plane);
-
-int ipu_plane_irq(struct ipu_plane *plane);
-
-#endif
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
deleted file mode 100644 (file)
index 015a454..0000000
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * i.MX drm driver - parallel display implementation
- *
- * Copyright (C) 2012 Sascha Hauer, Pengutronix
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
-
-#include <linux/component.h>
-#include <linux/module.h>
-#include <drm/drmP.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_panel.h>
-#include <linux/videodev2.h>
-#include <video/of_display_timing.h>
-
-#include "imx-drm.h"
-
-#define con_to_imxpd(x) container_of(x, struct imx_parallel_display, connector)
-#define enc_to_imxpd(x) container_of(x, struct imx_parallel_display, encoder)
-
-struct imx_parallel_display {
-       struct drm_connector connector;
-       struct drm_encoder encoder;
-       struct device *dev;
-       void *edid;
-       int edid_len;
-       u32 interface_pix_fmt;
-       int mode_valid;
-       struct drm_display_mode mode;
-       struct drm_panel *panel;
-};
-
-static enum drm_connector_status imx_pd_connector_detect(
-               struct drm_connector *connector, bool force)
-{
-       return connector_status_connected;
-}
-
-static int imx_pd_connector_get_modes(struct drm_connector *connector)
-{
-       struct imx_parallel_display *imxpd = con_to_imxpd(connector);
-       struct device_node *np = imxpd->dev->of_node;
-       int num_modes = 0;
-
-       if (imxpd->panel && imxpd->panel->funcs &&
-           imxpd->panel->funcs->get_modes) {
-               num_modes = imxpd->panel->funcs->get_modes(imxpd->panel);
-               if (num_modes > 0)
-                       return num_modes;
-       }
-
-       if (imxpd->edid) {
-               drm_mode_connector_update_edid_property(connector, imxpd->edid);
-               num_modes = drm_add_edid_modes(connector, imxpd->edid);
-       }
-
-       if (imxpd->mode_valid) {
-               struct drm_display_mode *mode = drm_mode_create(connector->dev);
-
-               if (!mode)
-                       return -EINVAL;
-               drm_mode_copy(mode, &imxpd->mode);
-               mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
-               drm_mode_probed_add(connector, mode);
-               num_modes++;
-       }
-
-       if (np) {
-               struct drm_display_mode *mode = drm_mode_create(connector->dev);
-
-               if (!mode)
-                       return -EINVAL;
-               of_get_drm_display_mode(np, &imxpd->mode, OF_USE_NATIVE_MODE);
-               drm_mode_copy(mode, &imxpd->mode);
-               mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
-               drm_mode_probed_add(connector, mode);
-               num_modes++;
-       }
-
-       return num_modes;
-}
-
-static struct drm_encoder *imx_pd_connector_best_encoder(
-               struct drm_connector *connector)
-{
-       struct imx_parallel_display *imxpd = con_to_imxpd(connector);
-
-       return &imxpd->encoder;
-}
-
-static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-       struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
-
-       if (mode != DRM_MODE_DPMS_ON)
-               drm_panel_disable(imxpd->panel);
-       else
-               drm_panel_enable(imxpd->panel);
-}
-
-static bool imx_pd_encoder_mode_fixup(struct drm_encoder *encoder,
-                          const struct drm_display_mode *mode,
-                          struct drm_display_mode *adjusted_mode)
-{
-       return true;
-}
-
-static void imx_pd_encoder_prepare(struct drm_encoder *encoder)
-{
-       struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
-
-       imx_drm_panel_format(encoder, imxpd->interface_pix_fmt);
-}
-
-static void imx_pd_encoder_commit(struct drm_encoder *encoder)
-{
-}
-
-static void imx_pd_encoder_mode_set(struct drm_encoder *encoder,
-                        struct drm_display_mode *mode,
-                        struct drm_display_mode *adjusted_mode)
-{
-}
-
-static void imx_pd_encoder_disable(struct drm_encoder *encoder)
-{
-}
-
-static struct drm_connector_funcs imx_pd_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .detect = imx_pd_connector_detect,
-       .destroy = imx_drm_connector_destroy,
-};
-
-static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
-       .get_modes = imx_pd_connector_get_modes,
-       .best_encoder = imx_pd_connector_best_encoder,
-};
-
-static struct drm_encoder_funcs imx_pd_encoder_funcs = {
-       .destroy = imx_drm_encoder_destroy,
-};
-
-static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
-       .dpms = imx_pd_encoder_dpms,
-       .mode_fixup = imx_pd_encoder_mode_fixup,
-       .prepare = imx_pd_encoder_prepare,
-       .commit = imx_pd_encoder_commit,
-       .mode_set = imx_pd_encoder_mode_set,
-       .disable = imx_pd_encoder_disable,
-};
-
-static int imx_pd_register(struct drm_device *drm,
-       struct imx_parallel_display *imxpd)
-{
-       int ret;
-
-       ret = imx_drm_encoder_parse_of(drm, &imxpd->encoder,
-                                      imxpd->dev->of_node);
-       if (ret)
-               return ret;
-
-       /* set the connector's dpms to OFF so that
-        * drm_helper_connector_dpms() won't return
-        * immediately since the current state is ON
-        * at this point.
-        */
-       imxpd->connector.dpms = DRM_MODE_DPMS_OFF;
-
-       drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs);
-       drm_encoder_init(drm, &imxpd->encoder, &imx_pd_encoder_funcs,
-                        DRM_MODE_ENCODER_NONE);
-
-       drm_connector_helper_add(&imxpd->connector,
-                       &imx_pd_connector_helper_funcs);
-       drm_connector_init(drm, &imxpd->connector, &imx_pd_connector_funcs,
-                          DRM_MODE_CONNECTOR_VGA);
-
-       if (imxpd->panel)
-               drm_panel_attach(imxpd->panel, &imxpd->connector);
-
-       drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
-
-       imxpd->connector.encoder = &imxpd->encoder;
-
-       return 0;
-}
-
-static int imx_pd_bind(struct device *dev, struct device *master, void *data)
-{
-       struct drm_device *drm = data;
-       struct device_node *np = dev->of_node;
-       struct device_node *panel_node;
-       const u8 *edidp;
-       struct imx_parallel_display *imxpd;
-       int ret;
-       const char *fmt;
-
-       imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL);
-       if (!imxpd)
-               return -ENOMEM;
-
-       edidp = of_get_property(np, "edid", &imxpd->edid_len);
-       if (edidp)
-               imxpd->edid = kmemdup(edidp, imxpd->edid_len, GFP_KERNEL);
-
-       ret = of_property_read_string(np, "interface-pix-fmt", &fmt);
-       if (!ret) {
-               if (!strcmp(fmt, "rgb24"))
-                       imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB24;
-               else if (!strcmp(fmt, "rgb565"))
-                       imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565;
-               else if (!strcmp(fmt, "bgr666"))
-                       imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666;
-               else if (!strcmp(fmt, "lvds666"))
-                       imxpd->interface_pix_fmt =
-                                       v4l2_fourcc('L', 'V', 'D', '6');
-       }
-
-       panel_node = of_parse_phandle(np, "fsl,panel", 0);
-       if (panel_node)
-               imxpd->panel = of_drm_find_panel(panel_node);
-
-       imxpd->dev = dev;
-
-       ret = imx_pd_register(drm, imxpd);
-       if (ret)
-               return ret;
-
-       dev_set_drvdata(dev, imxpd);
-
-       return 0;
-}
-
-static void imx_pd_unbind(struct device *dev, struct device *master,
-       void *data)
-{
-       struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
-
-       imxpd->encoder.funcs->destroy(&imxpd->encoder);
-       imxpd->connector.funcs->destroy(&imxpd->connector);
-}
-
-static const struct component_ops imx_pd_ops = {
-       .bind   = imx_pd_bind,
-       .unbind = imx_pd_unbind,
-};
-
-static int imx_pd_probe(struct platform_device *pdev)
-{
-       return component_add(&pdev->dev, &imx_pd_ops);
-}
-
-static int imx_pd_remove(struct platform_device *pdev)
-{
-       component_del(&pdev->dev, &imx_pd_ops);
-       return 0;
-}
-
-static const struct of_device_id imx_pd_dt_ids[] = {
-       { .compatible = "fsl,imx-parallel-display", },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, imx_pd_dt_ids);
-
-static struct platform_driver imx_pd_driver = {
-       .probe          = imx_pd_probe,
-       .remove         = imx_pd_remove,
-       .driver         = {
-               .of_match_table = imx_pd_dt_ids,
-               .name   = "imx-parallel-display",
-               .owner  = THIS_MODULE,
-       },
-};
-
-module_platform_driver(imx_pd_driver);
-
-MODULE_DESCRIPTION("i.MX parallel display driver");
-MODULE_AUTHOR("Sascha Hauer, Pengutronix");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-parallel-display");
index 9935e66935af191e25d1ee4fee4ff70564228f20..eddef9cd2e1662087a4595cc48382b88c121832f 100644 (file)
@@ -275,11 +275,11 @@ u8 rtw_sitesurvey_cmd(struct adapter  *padapter, struct ndis_802_11_ssid *ssid,
        if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
                rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1);
 
-       ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+       ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
        if (ph2c == NULL)
                return _FAIL;
 
-       psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_KERNEL);
+       psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_ATOMIC);
        if (psurveyPara == NULL) {
                kfree(ph2c);
                return _FAIL;
@@ -405,7 +405,7 @@ u8 rtw_joinbss_cmd(struct adapter  *padapter, struct wlan_network *pnetwork)
        else
                RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+Join cmd: SSid =[%s]\n", pmlmepriv->assoc_ssid.Ssid));
 
-       pcmd = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+       pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
        if (pcmd == NULL) {
                res = _FAIL;
                RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd: memory allocate for cmd_obj fail!!!\n"));
@@ -755,13 +755,13 @@ u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter)
        u8      res = _SUCCESS;
 
 
-       ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+       ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
        if (ph2c == NULL) {
                res = _FAIL;
                goto exit;
        }
 
-       pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_KERNEL);
+       pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
        if (pdrvextra_cmd_parm == NULL) {
                kfree(ph2c);
                res = _FAIL;
@@ -967,13 +967,13 @@ u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue)
        u8      res = _SUCCESS;
 
        if (enqueue) {
-               ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+               ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
                if (ph2c == NULL) {
                        res = _FAIL;
                        goto exit;
                }
 
-               pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_KERNEL);
+               pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
                if (pdrvextra_cmd_parm == NULL) {
                        kfree(ph2c);
                        res = _FAIL;
@@ -1010,13 +1010,13 @@ u8 rtw_rpt_timer_cfg_cmd(struct adapter *padapter, u16 min_time)
 
        u8      res = _SUCCESS;
 
-       ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+       ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
        if (ph2c == NULL) {
                res = _FAIL;
                goto exit;
        }
 
-       pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_KERNEL);
+       pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
        if (pdrvextra_cmd_parm == NULL) {
                kfree(ph2c);
                res = _FAIL;
@@ -1088,13 +1088,13 @@ u8 rtw_ps_cmd(struct adapter *padapter)
 
        u8      res = _SUCCESS;
 
-       ppscmd = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+       ppscmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
        if (ppscmd == NULL) {
                res = _FAIL;
                goto exit;
        }
 
-       pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_KERNEL);
+       pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
        if (pdrvextra_cmd_parm == NULL) {
                kfree(ppscmd);
                res = _FAIL;
index 5ba5099ec20d1af8fd4415b8dbeab8d3dd1fdcc8..70b1bc3e0e63333abaa5ee2a2f63e4778f3124c2 100644 (file)
@@ -4241,12 +4241,12 @@ void report_survey_event(struct adapter *padapter,
        pcmdpriv = &padapter->cmdpriv;
 
 
-       pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+       pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
        if (pcmd_obj == NULL)
                return;
 
        cmdsz = (sizeof(struct survey_event) + sizeof(struct C2HEvent_Header));
-       pevtcmd = kzalloc(cmdsz, GFP_KERNEL);
+       pevtcmd = kzalloc(cmdsz, GFP_ATOMIC);
        if (pevtcmd == NULL) {
                kfree(pcmd_obj);
                return;
@@ -4339,12 +4339,12 @@ void report_join_res(struct adapter *padapter, int res)
        struct mlme_ext_info    *pmlmeinfo = &(pmlmeext->mlmext_info);
        struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
 
-       pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+       pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
        if (pcmd_obj == NULL)
                return;
 
        cmdsz = (sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header));
-       pevtcmd = kzalloc(cmdsz, GFP_KERNEL);
+       pevtcmd = kzalloc(cmdsz, GFP_ATOMIC);
        if (pevtcmd == NULL) {
                kfree(pcmd_obj);
                return;
@@ -4854,11 +4854,11 @@ void survey_timer_hdl(void *function_context)
                        pmlmeext->scan_abort = false;/* reset */
                }
 
-               ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+               ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
                if (ph2c == NULL)
                        goto exit_survey_timer_hdl;
 
-               psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_KERNEL);
+               psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_ATOMIC);
                if (psurveyPara == NULL) {
                        kfree(ph2c);
                        goto exit_survey_timer_hdl;
index 33ccbbbd8ed6903fb8dd5ff61c26b9c89ca0e94c..d300369977fae5e51834ffd7f06962ea97db6195 100644 (file)
@@ -935,7 +935,7 @@ int rtw_check_bcn_info(struct adapter  *Adapter, u8 *pframe, u32 packet_len)
                return true;
        }
 
-       bssid = kzalloc(sizeof(struct wlan_bssid_ex), GFP_KERNEL);
+       bssid = kzalloc(sizeof(struct wlan_bssid_ex), GFP_ATOMIC);
 
        subtype = GetFrameSubType(pframe) >> 4;
 
index 407a318b09dbe2837dc64573792e6f886cc88d62..2f87150a21b7e2c1b3f09dd5df10d3085c8fda83 100644 (file)
@@ -47,6 +47,7 @@ static struct usb_device_id rtw_usb_id_tbl[] = {
        {USB_DEVICE(0x07b8, 0x8179)}, /* Abocom - Abocom */
        {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */
        {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */
+       {USB_DEVICE(0x2001, 0x3311)}, /* DLink GO-USB-N150 REV B1 */
        {USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */
        {}      /* Terminating entry */
 };
index b19e4329ba00739503215124ec768e8c99d843c3..73e58d22e325d8780d17470a9a9851a732669f89 100644 (file)
@@ -3491,7 +3491,7 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
                                len = sprintf(buf, "TargetAddress="
                                        "%s:%hu,%hu",
                                        inaddr_any ? conn->local_ip : np->np_ip,
-                                       inaddr_any ? conn->local_port : np->np_port,
+                                       np->np_port,
                                        tpg->tpgt);
                                len += 1;
 
index 8c60a1a1ae8dab96a63a382b572ecb7e83e1baf6..9f93b82340952d452ffe4807be7e06082c1e535a 100644 (file)
@@ -2738,7 +2738,8 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
        struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder;
        struct t10_reservation *pr_tmpl = &dev->t10_pr;
        u32 pr_res_mapped_lun = 0;
-       int all_reg = 0, calling_it_nexus = 0, released_regs = 0;
+       int all_reg = 0, calling_it_nexus = 0;
+       bool sa_res_key_unmatched = sa_res_key != 0;
        int prh_type = 0, prh_scope = 0;
 
        if (!se_sess)
@@ -2813,6 +2814,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
                        if (!all_reg) {
                                if (pr_reg->pr_res_key != sa_res_key)
                                        continue;
+                               sa_res_key_unmatched = false;
 
                                calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0;
                                pr_reg_nacl = pr_reg->pr_reg_nacl;
@@ -2820,7 +2822,6 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
                                __core_scsi3_free_registration(dev, pr_reg,
                                        (preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list :
                                                NULL, calling_it_nexus);
-                               released_regs++;
                        } else {
                                /*
                                 * Case for any existing all registrants type
@@ -2838,6 +2839,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
                                if ((sa_res_key) &&
                                     (pr_reg->pr_res_key != sa_res_key))
                                        continue;
+                               sa_res_key_unmatched = false;
 
                                calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0;
                                if (calling_it_nexus)
@@ -2848,7 +2850,6 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
                                __core_scsi3_free_registration(dev, pr_reg,
                                        (preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list :
                                                NULL, 0);
-                               released_regs++;
                        }
                        if (!calling_it_nexus)
                                core_scsi3_ua_allocate(pr_reg_nacl,
@@ -2863,7 +2864,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
                 * registered reservation key, then the device server shall
                 * complete the command with RESERVATION CONFLICT status.
                 */
-               if (!released_regs) {
+               if (sa_res_key_unmatched) {
                        spin_unlock(&dev->dev_reservation_lock);
                        core_scsi3_put_pr_reg(pr_reg_n);
                        return TCM_RESERVATION_CONFLICT;
index 9ea0d5f03f7a566fbbe4191a93ad1312cbcfa5af..be877bf6f7304a88fabb3506d65ac75542471b01 100644 (file)
@@ -2292,7 +2292,7 @@ transport_generic_new_cmd(struct se_cmd *cmd)
         * and let it call back once the write buffers are ready.
         */
        target_add_to_state_list(cmd);
-       if (cmd->data_direction != DMA_TO_DEVICE) {
+       if (cmd->data_direction != DMA_TO_DEVICE || cmd->data_length == 0) {
                target_execute_cmd(cmd);
                return 0;
        }
index 1ab0018271c5c622c0b7556fb92a3a1d9ad38e5b..ad09e51ffae4d097109241d9a19b97c97858109b 100644 (file)
@@ -50,15 +50,14 @@ struct cpufreq_cooling_device {
        unsigned int cpufreq_state;
        unsigned int cpufreq_val;
        struct cpumask allowed_cpus;
+       struct list_head node;
 };
 static DEFINE_IDR(cpufreq_idr);
 static DEFINE_MUTEX(cooling_cpufreq_lock);
 
 static unsigned int cpufreq_dev_count;
 
-/* notify_table passes value to the CPUFREQ_ADJUST callback function. */
-#define NOTIFY_INVALID NULL
-static struct cpufreq_cooling_device *notify_device;
+static LIST_HEAD(cpufreq_dev_list);
 
 /**
  * get_idr - function to get a unique id.
@@ -287,15 +286,12 @@ static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device,
 
        cpufreq_device->cpufreq_state = cooling_state;
        cpufreq_device->cpufreq_val = clip_freq;
-       notify_device = cpufreq_device;
 
        for_each_cpu(cpuid, mask) {
                if (is_cpufreq_valid(cpuid))
                        cpufreq_update_policy(cpuid);
        }
 
-       notify_device = NOTIFY_INVALID;
-
        return 0;
 }
 
@@ -316,21 +312,28 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb,
 {
        struct cpufreq_policy *policy = data;
        unsigned long max_freq = 0;
+       struct cpufreq_cooling_device *cpufreq_dev;
 
-       if (event != CPUFREQ_ADJUST || notify_device == NOTIFY_INVALID)
+       if (event != CPUFREQ_ADJUST)
                return 0;
 
-       if (cpumask_test_cpu(policy->cpu, &notify_device->allowed_cpus))
-               max_freq = notify_device->cpufreq_val;
-       else
-               return 0;
+       mutex_lock(&cooling_cpufreq_lock);
+       list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
+               if (!cpumask_test_cpu(policy->cpu,
+                                       &cpufreq_dev->allowed_cpus))
+                       continue;
+
+               if (!cpufreq_dev->cpufreq_val)
+                       cpufreq_dev->cpufreq_val = get_cpu_frequency(
+                                       cpumask_any(&cpufreq_dev->allowed_cpus),
+                                       cpufreq_dev->cpufreq_state);
 
-       /* Never exceed user_policy.max */
-       if (max_freq > policy->user_policy.max)
-               max_freq = policy->user_policy.max;
+               max_freq = cpufreq_dev->cpufreq_val;
 
-       if (policy->max != max_freq)
-               cpufreq_verify_within_limits(policy, 0, max_freq);
+               if (policy->max != max_freq)
+                       cpufreq_verify_within_limits(policy, 0, max_freq);
+       }
+       mutex_unlock(&cooling_cpufreq_lock);
 
        return 0;
 }
@@ -486,6 +489,7 @@ __cpufreq_cooling_register(struct device_node *np,
                cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
                                          CPUFREQ_POLICY_NOTIFIER);
        cpufreq_dev_count++;
+       list_add(&cpufreq_dev->node, &cpufreq_dev_list);
 
        mutex_unlock(&cooling_cpufreq_lock);
 
@@ -549,6 +553,7 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
 
        cpufreq_dev = cdev->devdata;
        mutex_lock(&cooling_cpufreq_lock);
+       list_del(&cpufreq_dev->node);
        cpufreq_dev_count--;
 
        /* Unregister the notifier for the last cpufreq cooling device */
index 3f5ad25ddca811cf5a9c61509af9ac8c89550b28..b6be572704a4c7ff97055f1cb273ff3016399469 100644 (file)
@@ -417,13 +417,10 @@ void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf)
 
        th_zone = sensor_conf->pzone_data;
 
-       if (th_zone->therm_dev)
-               thermal_zone_device_unregister(th_zone->therm_dev);
+       thermal_zone_device_unregister(th_zone->therm_dev);
 
-       for (i = 0; i < th_zone->cool_dev_size; i++) {
-               if (th_zone->cool_dev[i])
-                       cpufreq_cooling_unregister(th_zone->cool_dev[i]);
-       }
+       for (i = 0; i < th_zone->cool_dev_size; ++i)
+               cpufreq_cooling_unregister(th_zone->cool_dev[i]);
 
        dev_info(sensor_conf->dev,
                "Exynos: Kernel Thermal management unregistered\n");
index 90163b384660247b343d9fc551dfe067128d6219..d1ec5804c0bb94cebeb22d5038b4861393047ba0 100644 (file)
@@ -275,6 +275,7 @@ int st_thermal_unregister(struct platform_device *pdev)
 }
 EXPORT_SYMBOL_GPL(st_thermal_unregister);
 
+#ifdef CONFIG_PM_SLEEP
 static int st_thermal_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -305,6 +306,8 @@ static int st_thermal_resume(struct device *dev)
 
        return 0;
 }
+#endif
+
 SIMPLE_DEV_PM_OPS(st_thermal_pm_ops, st_thermal_suspend, st_thermal_resume);
 EXPORT_SYMBOL_GPL(st_thermal_pm_ops);
 
index 56982da4a9e9f77ac4fd062f95c00724cc7ade34..bf355050eab695f50c6220589faf69a0b9e3b6b6 100644 (file)
@@ -240,32 +240,6 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int of_serial_suspend(struct device *dev)
-{
-       struct of_serial_info *info = dev_get_drvdata(dev);
-
-       serial8250_suspend_port(info->line);
-       if (info->clk)
-               clk_disable_unprepare(info->clk);
-
-       return 0;
-}
-
-static int of_serial_resume(struct device *dev)
-{
-       struct of_serial_info *info = dev_get_drvdata(dev);
-
-       if (info->clk)
-               clk_prepare_enable(info->clk);
-
-       serial8250_resume_port(info->line);
-
-       return 0;
-}
-#endif
-static SIMPLE_DEV_PM_OPS(of_serial_pm_ops, of_serial_suspend, of_serial_resume);
-
 /*
  * A few common types, add more as needed.
  */
@@ -297,7 +271,6 @@ static struct platform_driver of_platform_serial_driver = {
                .name = "of_serial",
                .owner = THIS_MODULE,
                .of_match_table = of_platform_serial_table,
-               .pm = &of_serial_pm_ops,
        },
        .probe = of_platform_serial_probe,
        .remove = of_platform_serial_remove,
index 39b4081b632df2ce600501add8c011c7dbde75b3..96fafed92b76b0972401a13b4eb67a5b1dfdddb1 100644 (file)
@@ -44,6 +44,9 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* Creative SB Audigy 2 NX */
        { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
 
+       /* Microsoft Wireless Laser Mouse 6000 Receiver */
+       { USB_DEVICE(0x045e, 0x00e1), .driver_info = USB_QUIRK_RESET_RESUME },
+
        /* Microsoft LifeCam-VX700 v2.0 */
        { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME },
 
index 711b23019d541f1fcc589e93a22d80ef677ec207..df38e7ef49761ce87f3532c37c556a1399ab8199 100644 (file)
@@ -791,6 +791,10 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
 
        trb = dwc->ep0_trb;
 
+       r = next_request(&ep0->request_list);
+       if (!r)
+               return;
+
        status = DWC3_TRB_SIZE_TRBSTS(trb->size);
        if (status == DWC3_TRBSTS_SETUP_PENDING) {
                dwc3_trace(trace_dwc3_ep0, "Setup Pending received");
@@ -801,10 +805,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
                return;
        }
 
-       r = next_request(&ep0->request_list);
-       if (!r)
-               return;
-
        ur = &r->request;
 
        length = trb->size & DWC3_TRB_SIZE_MASK;
index 696160d48ae8521651f4f313ee9998288c245ab4..388cfd83b6b667a8e40dffc6c61d9257839f2f81 100644 (file)
@@ -22,7 +22,6 @@
 
 
 #include <linux/slab.h>
-#include <linux/device.h>
 #include <asm/unaligned.h>
 
 #include "xhci.h"
@@ -1149,9 +1148,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
                 * including the USB 3.0 roothub, but only if CONFIG_PM_RUNTIME
                 * is enabled, so also enable remote wake here.
                 */
-               if (hcd->self.root_hub->do_remote_wakeup
-                               && device_may_wakeup(hcd->self.controller)) {
-
+               if (hcd->self.root_hub->do_remote_wakeup) {
                        if (t1 & PORT_CONNECT) {
                                t2 |= PORT_WKOC_E | PORT_WKDISC_E;
                                t2 &= ~PORT_WKCONN_E;
index 9a69b1f1b300889d56200ac35d6d1cf22195c588..142b601f95636fdff622bca8c4fb1a9aef87093b 100644 (file)
@@ -281,7 +281,7 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
        if (xhci->quirks & XHCI_COMP_MODE_QUIRK)
                pdev->no_d3cold = true;
 
-       return xhci_suspend(xhci);
+       return xhci_suspend(xhci, do_wakeup);
 }
 
 static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
index 3d78b0cd674b4cd07485dfe493b3cd67d0253fdf..646300cbe5f75d34fabf3fd4d13d1100c52e97c0 100644 (file)
@@ -204,7 +204,15 @@ static int xhci_plat_suspend(struct device *dev)
        struct usb_hcd  *hcd = dev_get_drvdata(dev);
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 
-       return xhci_suspend(xhci);
+       /*
+        * xhci_suspend() needs `do_wakeup` to know whether host is allowed
+        * to do wakeup during suspend. Since xhci_plat_suspend is currently
+        * only designed for system suspend, device_may_wakeup() is enough
+        * to dertermine whether host is allowed to do wakeup. Need to
+        * reconsider this when xhci_plat_suspend enlarges its scope, e.g.,
+        * also applies to runtime suspend.
+        */
+       return xhci_suspend(xhci, device_may_wakeup(dev));
 }
 
 static int xhci_plat_resume(struct device *dev)
index bc6fcbc16f61ec820ba93d5fb6700cfcbd0ae2a2..06433aec81d71511f0583a1099d42d9977f8da3b 100644 (file)
@@ -1067,9 +1067,8 @@ static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id,
                                false);
                xhci_ring_cmd_db(xhci);
        } else {
-               /* Clear our internal halted state and restart the ring(s) */
+               /* Clear our internal halted state */
                xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED;
-               ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
        }
 }
 
@@ -1823,22 +1822,13 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
                ep->stopped_td = td;
                return 0;
        } else {
-               if (trb_comp_code == COMP_STALL) {
-                       /* The transfer is completed from the driver's
-                        * perspective, but we need to issue a set dequeue
-                        * command for this stalled endpoint to move the dequeue
-                        * pointer past the TD.  We can't do that here because
-                        * the halt condition must be cleared first.  Let the
-                        * USB class driver clear the stall later.
-                        */
-                       ep->stopped_td = td;
-                       ep->stopped_stream = ep_ring->stream_id;
-               } else if (xhci_requires_manual_halt_cleanup(xhci,
-                                       ep_ctx, trb_comp_code)) {
-                       /* Other types of errors halt the endpoint, but the
-                        * class driver doesn't call usb_reset_endpoint() unless
-                        * the error is -EPIPE.  Clear the halted status in the
-                        * xHCI hardware manually.
+               if (trb_comp_code == COMP_STALL ||
+                   xhci_requires_manual_halt_cleanup(xhci, ep_ctx,
+                                                     trb_comp_code)) {
+                       /* Issue a reset endpoint command to clear the host side
+                        * halt, followed by a set dequeue command to move the
+                        * dequeue pointer past the TD.
+                        * The class driver clears the device side halt later.
                         */
                        xhci_cleanup_halted_endpoint(xhci,
                                        slot_id, ep_index, ep_ring->stream_id,
@@ -1958,9 +1948,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
                else
                        td->urb->actual_length = 0;
 
-               xhci_cleanup_halted_endpoint(xhci,
-                       slot_id, ep_index, 0, td, event_trb);
-               return finish_td(xhci, td, event_trb, event, ep, status, true);
+               return finish_td(xhci, td, event_trb, event, ep, status, false);
        }
        /*
         * Did we transfer any data, despite the errors that might have
@@ -2519,17 +2507,8 @@ cleanup:
                if (ret) {
                        urb = td->urb;
                        urb_priv = urb->hcpriv;
-                       /* Leave the TD around for the reset endpoint function
-                        * to use(but only if it's not a control endpoint,
-                        * since we already queued the Set TR dequeue pointer
-                        * command for stalled control endpoints).
-                        */
-                       if (usb_endpoint_xfer_control(&urb->ep->desc) ||
-                               (trb_comp_code != COMP_STALL &&
-                                       trb_comp_code != COMP_BABBLE))
-                               xhci_urb_free_priv(xhci, urb_priv);
-                       else
-                               kfree(urb_priv);
+
+                       xhci_urb_free_priv(xhci, urb_priv);
 
                        usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
                        if ((urb->actual_length != urb->transfer_buffer_length &&
index 2a5d45b4cb15ef30d82294de6c5d8e015449a383..033b46c470bdff8120b1e903ee3debbb9b998218 100644 (file)
@@ -35,6 +35,8 @@
 #define DRIVER_AUTHOR "Sarah Sharp"
 #define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
 
+#define        PORT_WAKE_BITS  (PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E)
+
 /* Some 0.95 hardware can't handle the chain bit on a Link TRB being cleared */
 static int link_quirk;
 module_param(link_quirk, int, S_IRUGO | S_IWUSR);
@@ -851,13 +853,47 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci)
        xhci_set_cmd_ring_deq(xhci);
 }
 
+static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci)
+{
+       int port_index;
+       __le32 __iomem **port_array;
+       unsigned long flags;
+       u32 t1, t2;
+
+       spin_lock_irqsave(&xhci->lock, flags);
+
+       /* disble usb3 ports Wake bits*/
+       port_index = xhci->num_usb3_ports;
+       port_array = xhci->usb3_ports;
+       while (port_index--) {
+               t1 = readl(port_array[port_index]);
+               t1 = xhci_port_state_to_neutral(t1);
+               t2 = t1 & ~PORT_WAKE_BITS;
+               if (t1 != t2)
+                       writel(t2, port_array[port_index]);
+       }
+
+       /* disble usb2 ports Wake bits*/
+       port_index = xhci->num_usb2_ports;
+       port_array = xhci->usb2_ports;
+       while (port_index--) {
+               t1 = readl(port_array[port_index]);
+               t1 = xhci_port_state_to_neutral(t1);
+               t2 = t1 & ~PORT_WAKE_BITS;
+               if (t1 != t2)
+                       writel(t2, port_array[port_index]);
+       }
+
+       spin_unlock_irqrestore(&xhci->lock, flags);
+}
+
 /*
  * Stop HC (not bus-specific)
  *
  * This is called when the machine transition into S3/S4 mode.
  *
  */
-int xhci_suspend(struct xhci_hcd *xhci)
+int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
 {
        int                     rc = 0;
        unsigned int            delay = XHCI_MAX_HALT_USEC;
@@ -868,6 +904,10 @@ int xhci_suspend(struct xhci_hcd *xhci)
                        xhci->shared_hcd->state != HC_STATE_SUSPENDED)
                return -EINVAL;
 
+       /* Clear root port wake on bits if wakeup not allowed. */
+       if (!do_wakeup)
+               xhci_disable_port_wake_on_bits(xhci);
+
        /* Don't poll the roothubs on bus suspend. */
        xhci_dbg(xhci, "%s: stopping port polling.\n", __func__);
        clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
@@ -2912,68 +2952,33 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
        }
 }
 
-/* Deal with stalled endpoints.  The core should have sent the control message
- * to clear the halt condition.  However, we need to make the xHCI hardware
- * reset its sequence number, since a device will expect a sequence number of
- * zero after the halt condition is cleared.
+/* Called when clearing halted device. The core should have sent the control
+ * message to clear the device halt condition. The host side of the halt should
+ * already be cleared with a reset endpoint command issued when the STALL tx
+ * event was received.
+ *
  * Context: in_interrupt
  */
+
 void xhci_endpoint_reset(struct usb_hcd *hcd,
                struct usb_host_endpoint *ep)
 {
        struct xhci_hcd *xhci;
-       struct usb_device *udev;
-       unsigned int ep_index;
-       unsigned long flags;
-       int ret;
-       struct xhci_virt_ep *virt_ep;
-       struct xhci_command *command;
 
        xhci = hcd_to_xhci(hcd);
-       udev = (struct usb_device *) ep->hcpriv;
-       /* Called with a root hub endpoint (or an endpoint that wasn't added
-        * with xhci_add_endpoint()
-        */
-       if (!ep->hcpriv)
-               return;
-       ep_index = xhci_get_endpoint_index(&ep->desc);
-       virt_ep = &xhci->devs[udev->slot_id]->eps[ep_index];
-       if (!virt_ep->stopped_td) {
-               xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
-                       "Endpoint 0x%x not halted, refusing to reset.",
-                       ep->desc.bEndpointAddress);
-               return;
-       }
-       if (usb_endpoint_xfer_control(&ep->desc)) {
-               xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
-                               "Control endpoint stall already handled.");
-               return;
-       }
 
-       command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC);
-       if (!command)
-               return;
-
-       xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
-                       "Queueing reset endpoint command");
-       spin_lock_irqsave(&xhci->lock, flags);
-       ret = xhci_queue_reset_ep(xhci, command, udev->slot_id, ep_index);
        /*
-        * Can't change the ring dequeue pointer until it's transitioned to the
-        * stopped state, which is only upon a successful reset endpoint
-        * command.  Better hope that last command worked!
+        * We might need to implement the config ep cmd in xhci 4.8.1 note:
+        * The Reset Endpoint Command may only be issued to endpoints in the
+        * Halted state. If software wishes reset the Data Toggle or Sequence
+        * Number of an endpoint that isn't in the Halted state, then software
+        * may issue a Configure Endpoint Command with the Drop and Add bits set
+        * for the target endpoint. that is in the Stopped state.
         */
-       if (!ret) {
-               xhci_cleanup_stalled_ring(xhci, udev, ep_index);
-               kfree(virt_ep->stopped_td);
-               xhci_ring_cmd_db(xhci);
-       }
-       virt_ep->stopped_td = NULL;
-       virt_ep->stopped_stream = 0;
-       spin_unlock_irqrestore(&xhci->lock, flags);
 
-       if (ret)
-               xhci_warn(xhci, "FIXME allocate a new ring segment\n");
+       /* For now just print debug to follow the situation */
+       xhci_dbg(xhci, "Endpoint 0x%x ep reset callback called\n",
+                ep->desc.bEndpointAddress);
 }
 
 static int xhci_check_streams_endpoint(struct xhci_hcd *xhci,
index df76d642e7190bd04854a10024c06714dd7e48d0..d745715a1e2f53648b1e1c2b1288f9c963bb42be 100644 (file)
@@ -1746,7 +1746,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks);
 void xhci_init_driver(struct hc_driver *drv, int (*setup_fn)(struct usb_hcd *));
 
 #ifdef CONFIG_PM
-int xhci_suspend(struct xhci_hcd *xhci);
+int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup);
 int xhci_resume(struct xhci_hcd *xhci, bool hibernated);
 #else
 #define        xhci_suspend    NULL
index cfd009dc401826cc8e052325249c791bf8a959d6..6c4eb3cf5efd599653641e5d96d20b05610a6ed5 100644 (file)
@@ -120,6 +120,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */
        { USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */
        { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */
+       { USB_DEVICE(0x10C4, 0x8875) }, /* CEL MeshConnect USB Stick */
        { USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */
        { USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */
        { USB_DEVICE(0x10C4, 0x8946) }, /* Ketra N1 Wireless Interface */
index 0dad8ce5a60946431e41f38683971dfc8f1dab13..1ebb351b9e9a59c9dbd90ffda56cae1769de764e 100644 (file)
@@ -470,6 +470,39 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FD_PID) },
        { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FE_PID) },
        { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FF_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_4701_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9300_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9301_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9302_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9303_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9304_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9305_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9306_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9307_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9308_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9309_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930A_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930B_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930C_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930D_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930E_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930F_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9310_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9311_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9312_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9313_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9314_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9315_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9316_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9317_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9318_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9319_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931A_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931B_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931C_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931D_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931E_PID) },
+       { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931F_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) },
index 6786b705ccf606ca47cb471d76b25c4b2981bf10..e52409c9be999f817cbdb627f4be8ec6f127cbe6 100644 (file)
 #define BAYER_CONTOUR_CABLE_PID        0x6001
 
 /*
- * The following are the values for the Matrix Orbital FTDI Range
- * Anything in this range will use an FT232RL.
+ * Matrix Orbital Intelligent USB displays.
+ * http://www.matrixorbital.com
  */
 #define MTXORB_VID                     0x1B3D
 #define MTXORB_FTDI_RANGE_0100_PID     0x0100
 #define MTXORB_FTDI_RANGE_01FD_PID     0x01FD
 #define MTXORB_FTDI_RANGE_01FE_PID     0x01FE
 #define MTXORB_FTDI_RANGE_01FF_PID     0x01FF
-
-
+#define MTXORB_FTDI_RANGE_4701_PID     0x4701
+#define MTXORB_FTDI_RANGE_9300_PID     0x9300
+#define MTXORB_FTDI_RANGE_9301_PID     0x9301
+#define MTXORB_FTDI_RANGE_9302_PID     0x9302
+#define MTXORB_FTDI_RANGE_9303_PID     0x9303
+#define MTXORB_FTDI_RANGE_9304_PID     0x9304
+#define MTXORB_FTDI_RANGE_9305_PID     0x9305
+#define MTXORB_FTDI_RANGE_9306_PID     0x9306
+#define MTXORB_FTDI_RANGE_9307_PID     0x9307
+#define MTXORB_FTDI_RANGE_9308_PID     0x9308
+#define MTXORB_FTDI_RANGE_9309_PID     0x9309
+#define MTXORB_FTDI_RANGE_930A_PID     0x930A
+#define MTXORB_FTDI_RANGE_930B_PID     0x930B
+#define MTXORB_FTDI_RANGE_930C_PID     0x930C
+#define MTXORB_FTDI_RANGE_930D_PID     0x930D
+#define MTXORB_FTDI_RANGE_930E_PID     0x930E
+#define MTXORB_FTDI_RANGE_930F_PID     0x930F
+#define MTXORB_FTDI_RANGE_9310_PID     0x9310
+#define MTXORB_FTDI_RANGE_9311_PID     0x9311
+#define MTXORB_FTDI_RANGE_9312_PID     0x9312
+#define MTXORB_FTDI_RANGE_9313_PID     0x9313
+#define MTXORB_FTDI_RANGE_9314_PID     0x9314
+#define MTXORB_FTDI_RANGE_9315_PID     0x9315
+#define MTXORB_FTDI_RANGE_9316_PID     0x9316
+#define MTXORB_FTDI_RANGE_9317_PID     0x9317
+#define MTXORB_FTDI_RANGE_9318_PID     0x9318
+#define MTXORB_FTDI_RANGE_9319_PID     0x9319
+#define MTXORB_FTDI_RANGE_931A_PID     0x931A
+#define MTXORB_FTDI_RANGE_931B_PID     0x931B
+#define MTXORB_FTDI_RANGE_931C_PID     0x931C
+#define MTXORB_FTDI_RANGE_931D_PID     0x931D
+#define MTXORB_FTDI_RANGE_931E_PID     0x931E
+#define MTXORB_FTDI_RANGE_931F_PID     0x931F
 
 /*
  * The Mobility Lab (TML)
index 93cb7cebda62760bcaae46f3710e7477ff59a507..077c714f1285171ee3b9e4c418e0df42f60cd42c 100644 (file)
@@ -311,24 +311,30 @@ static void       usa26_indat_callback(struct urb *urb)
                if ((data[0] & 0x80) == 0) {
                        /* no errors on individual bytes, only
                           possible overrun err */
-                       if (data[0] & RXERROR_OVERRUN)
-                               err = TTY_OVERRUN;
-                       else
-                               err = 0;
+                       if (data[0] & RXERROR_OVERRUN) {
+                               tty_insert_flip_char(&port->port, 0,
+                                                               TTY_OVERRUN);
+                       }
                        for (i = 1; i < urb->actual_length ; ++i)
-                               tty_insert_flip_char(&port->port, data[i], err);
+                               tty_insert_flip_char(&port->port, data[i],
+                                                               TTY_NORMAL);
                } else {
                        /* some bytes had errors, every byte has status */
                        dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
                        for (i = 0; i + 1 < urb->actual_length; i += 2) {
-                               int stat = data[i], flag = 0;
-                               if (stat & RXERROR_OVERRUN)
-                                       flag |= TTY_OVERRUN;
-                               if (stat & RXERROR_FRAMING)
-                                       flag |= TTY_FRAME;
-                               if (stat & RXERROR_PARITY)
-                                       flag |= TTY_PARITY;
+                               int stat = data[i];
+                               int flag = TTY_NORMAL;
+
+                               if (stat & RXERROR_OVERRUN) {
+                                       tty_insert_flip_char(&port->port, 0,
+                                                               TTY_OVERRUN);
+                               }
                                /* XXX should handle break (0x10) */
+                               if (stat & RXERROR_PARITY)
+                                       flag = TTY_PARITY;
+                               else if (stat & RXERROR_FRAMING)
+                                       flag = TTY_FRAME;
+
                                tty_insert_flip_char(&port->port, data[i+1],
                                                flag);
                        }
@@ -649,14 +655,19 @@ static void       usa49_indat_callback(struct urb *urb)
                } else {
                        /* some bytes had errors, every byte has status */
                        for (i = 0; i + 1 < urb->actual_length; i += 2) {
-                               int stat = data[i], flag = 0;
-                               if (stat & RXERROR_OVERRUN)
-                                       flag |= TTY_OVERRUN;
-                               if (stat & RXERROR_FRAMING)
-                                       flag |= TTY_FRAME;
-                               if (stat & RXERROR_PARITY)
-                                       flag |= TTY_PARITY;
+                               int stat = data[i];
+                               int flag = TTY_NORMAL;
+
+                               if (stat & RXERROR_OVERRUN) {
+                                       tty_insert_flip_char(&port->port, 0,
+                                                               TTY_OVERRUN);
+                               }
                                /* XXX should handle break (0x10) */
+                               if (stat & RXERROR_PARITY)
+                                       flag = TTY_PARITY;
+                               else if (stat & RXERROR_FRAMING)
+                                       flag = TTY_FRAME;
+
                                tty_insert_flip_char(&port->port, data[i+1],
                                                flag);
                        }
@@ -713,15 +724,19 @@ static void usa49wg_indat_callback(struct urb *urb)
                         */
                        for (x = 0; x + 1 < len &&
                                    i + 1 < urb->actual_length; x += 2) {
-                               int stat = data[i], flag = 0;
+                               int stat = data[i];
+                               int flag = TTY_NORMAL;
 
-                               if (stat & RXERROR_OVERRUN)
-                                       flag |= TTY_OVERRUN;
-                               if (stat & RXERROR_FRAMING)
-                                       flag |= TTY_FRAME;
-                               if (stat & RXERROR_PARITY)
-                                       flag |= TTY_PARITY;
+                               if (stat & RXERROR_OVERRUN) {
+                                       tty_insert_flip_char(&port->port, 0,
+                                                               TTY_OVERRUN);
+                               }
                                /* XXX should handle break (0x10) */
+                               if (stat & RXERROR_PARITY)
+                                       flag = TTY_PARITY;
+                               else if (stat & RXERROR_FRAMING)
+                                       flag = TTY_FRAME;
+
                                tty_insert_flip_char(&port->port, data[i+1],
                                                     flag);
                                i += 2;
@@ -773,25 +788,31 @@ static void usa90_indat_callback(struct urb *urb)
                        if ((data[0] & 0x80) == 0) {
                                /* no errors on individual bytes, only
                                   possible overrun err*/
-                               if (data[0] & RXERROR_OVERRUN)
-                                       err = TTY_OVERRUN;
-                               else
-                                       err = 0;
+                               if (data[0] & RXERROR_OVERRUN) {
+                                       tty_insert_flip_char(&port->port, 0,
+                                                               TTY_OVERRUN);
+                               }
                                for (i = 1; i < urb->actual_length ; ++i)
                                        tty_insert_flip_char(&port->port,
-                                                       data[i], err);
+                                                       data[i], TTY_NORMAL);
                        }  else {
                        /* some bytes had errors, every byte has status */
                                dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
                                for (i = 0; i + 1 < urb->actual_length; i += 2) {
-                                       int stat = data[i], flag = 0;
-                                       if (stat & RXERROR_OVERRUN)
-                                               flag |= TTY_OVERRUN;
-                                       if (stat & RXERROR_FRAMING)
-                                               flag |= TTY_FRAME;
-                                       if (stat & RXERROR_PARITY)
-                                               flag |= TTY_PARITY;
+                                       int stat = data[i];
+                                       int flag = TTY_NORMAL;
+
+                                       if (stat & RXERROR_OVERRUN) {
+                                               tty_insert_flip_char(
+                                                               &port->port, 0,
+                                                               TTY_OVERRUN);
+                                       }
                                        /* XXX should handle break (0x10) */
+                                       if (stat & RXERROR_PARITY)
+                                               flag = TTY_PARITY;
+                                       else if (stat & RXERROR_FRAMING)
+                                               flag = TTY_FRAME;
+
                                        tty_insert_flip_char(&port->port,
                                                        data[i+1], flag);
                                }
index a7fe664b6b7d164e628c5b466e548efe7e10e7ec..70a098de429fc39934ef8808d3e6c5011f063352 100644 (file)
@@ -490,10 +490,9 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr,
                        if (*tty_flag == TTY_NORMAL)
                                *tty_flag = TTY_FRAME;
                }
-               if (lsr & UART_LSR_OE){
+               if (lsr & UART_LSR_OE) {
                        port->icount.overrun++;
-                       if (*tty_flag == TTY_NORMAL)
-                               *tty_flag = TTY_OVERRUN;
+                       tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
                }
        }
 
@@ -511,12 +510,8 @@ static void ssu100_process_read_urb(struct urb *urb)
        if ((len >= 4) &&
            (packet[0] == 0x1b) && (packet[1] == 0x1b) &&
            ((packet[2] == 0x00) || (packet[2] == 0x01))) {
-               if (packet[2] == 0x00) {
+               if (packet[2] == 0x00)
                        ssu100_update_lsr(port, packet[3], &flag);
-                       if (flag == TTY_OVERRUN)
-                               tty_insert_flip_char(&port->port, 0,
-                                               TTY_OVERRUN);
-               }
                if (packet[2] == 0x01)
                        ssu100_update_msr(port, packet[3]);
 
index 2fefaf923e4a2ecc6e3fd39b32f05631478806ed..18a283d6de1c8bd18663b57bbf7499510c49fa2d 100644 (file)
@@ -103,3 +103,10 @@ UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999,
                "VL711",
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_ATA_1X),
+
+/* Reported-by: Hans de Goede <hdegoede@redhat.com> */
+UNUSUAL_DEV(0x4971, 0x1012, 0x0000, 0x9999,
+               "Hitachi",
+               "External HDD",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_IGNORE_UAS),
index 69906cacd04fdc8b3d5236dc030e8bcf749c541f..a17f11850669b461130610692d558dd7e499258b 100644 (file)
@@ -1312,6 +1312,7 @@ static int
 vhost_scsi_set_endpoint(struct vhost_scsi *vs,
                        struct vhost_scsi_target *t)
 {
+       struct se_portal_group *se_tpg;
        struct tcm_vhost_tport *tv_tport;
        struct tcm_vhost_tpg *tpg;
        struct tcm_vhost_tpg **vs_tpg;
@@ -1359,6 +1360,21 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs,
                                ret = -EEXIST;
                                goto out;
                        }
+                       /*
+                        * In order to ensure individual vhost-scsi configfs
+                        * groups cannot be removed while in use by vhost ioctl,
+                        * go ahead and take an explicit se_tpg->tpg_group.cg_item
+                        * dependency now.
+                        */
+                       se_tpg = &tpg->se_tpg;
+                       ret = configfs_depend_item(se_tpg->se_tpg_tfo->tf_subsys,
+                                                  &se_tpg->tpg_group.cg_item);
+                       if (ret) {
+                               pr_warn("configfs_depend_item() failed: %d\n", ret);
+                               kfree(vs_tpg);
+                               mutex_unlock(&tpg->tv_tpg_mutex);
+                               goto out;
+                       }
                        tpg->tv_tpg_vhost_count++;
                        tpg->vhost_scsi = vs;
                        vs_tpg[tpg->tport_tpgt] = tpg;
@@ -1401,6 +1417,7 @@ static int
 vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
                          struct vhost_scsi_target *t)
 {
+       struct se_portal_group *se_tpg;
        struct tcm_vhost_tport *tv_tport;
        struct tcm_vhost_tpg *tpg;
        struct vhost_virtqueue *vq;
@@ -1449,6 +1466,13 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
                vs->vs_tpg[target] = NULL;
                match = true;
                mutex_unlock(&tpg->tv_tpg_mutex);
+               /*
+                * Release se_tpg->tpg_group.cg_item configfs dependency now
+                * to allow vhost-scsi WWPN se_tpg->tpg_group shutdown to occur.
+                */
+               se_tpg = &tpg->se_tpg;
+               configfs_undepend_item(se_tpg->se_tpg_tfo->tf_subsys,
+                                      &se_tpg->tpg_group.cg_item);
        }
        if (match) {
                for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
index 34a1b9dea6dda9824eda07022cb544db83066eed..da0bbb456d3fcf6fee384b9287566cb64c5ae04a 100644 (file)
@@ -104,7 +104,7 @@ obj-$(CONFIG_QNX6FS_FS)             += qnx6/
 obj-$(CONFIG_AUTOFS4_FS)       += autofs4/
 obj-$(CONFIG_ADFS_FS)          += adfs/
 obj-$(CONFIG_FUSE_FS)          += fuse/
-obj-$(CONFIG_OVERLAYFS_FS)     += overlayfs/
+obj-$(CONFIG_OVERLAY_FS)       += overlayfs/
 obj-$(CONFIG_UDF_FS)           += udf/
 obj-$(CONFIG_SUN_OPENPROMFS)   += openpromfs/
 obj-$(CONFIG_OMFS_FS)          += omfs/
index 84a751005f5b8ad0f0f5cd6e3c5ec67df5f7440c..14b93159ef83a140483bb31a4a6c70286d209ed8 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -165,6 +165,15 @@ static struct vfsmount *aio_mnt;
 static const struct file_operations aio_ring_fops;
 static const struct address_space_operations aio_ctx_aops;
 
+/* Backing dev info for aio fs.
+ * -no dirty page accounting or writeback happens
+ */
+static struct backing_dev_info aio_fs_backing_dev_info = {
+       .name           = "aiofs",
+       .state          = 0,
+       .capabilities   = BDI_CAP_NO_ACCT_AND_WRITEBACK | BDI_CAP_MAP_COPY,
+};
+
 static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages)
 {
        struct qstr this = QSTR_INIT("[aio]", 5);
@@ -176,6 +185,7 @@ static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages)
 
        inode->i_mapping->a_ops = &aio_ctx_aops;
        inode->i_mapping->private_data = ctx;
+       inode->i_mapping->backing_dev_info = &aio_fs_backing_dev_info;
        inode->i_size = PAGE_SIZE * nr_pages;
 
        path.dentry = d_alloc_pseudo(aio_mnt->mnt_sb, &this);
@@ -220,6 +230,9 @@ static int __init aio_setup(void)
        if (IS_ERR(aio_mnt))
                panic("Failed to create aio fs mount.");
 
+       if (bdi_init(&aio_fs_backing_dev_info))
+               panic("Failed to init aio fs backing dev info.");
+
        kiocb_cachep = KMEM_CACHE(kiocb, SLAB_HWCACHE_ALIGN|SLAB_PANIC);
        kioctx_cachep = KMEM_CACHE(kioctx,SLAB_HWCACHE_ALIGN|SLAB_PANIC);
 
@@ -281,11 +294,6 @@ static const struct file_operations aio_ring_fops = {
        .mmap = aio_ring_mmap,
 };
 
-static int aio_set_page_dirty(struct page *page)
-{
-       return 0;
-}
-
 #if IS_ENABLED(CONFIG_MIGRATION)
 static int aio_migratepage(struct address_space *mapping, struct page *new,
                        struct page *old, enum migrate_mode mode)
@@ -357,7 +365,7 @@ out:
 #endif
 
 static const struct address_space_operations aio_ctx_aops = {
-       .set_page_dirty = aio_set_page_dirty,
+       .set_page_dirty = __set_page_dirty_no_writeback,
 #if IS_ENABLED(CONFIG_MIGRATION)
        .migratepage    = aio_migratepage,
 #endif
@@ -412,7 +420,6 @@ static int aio_setup_ring(struct kioctx *ctx)
                pr_debug("pid(%d) page[%d]->count=%d\n",
                         current->pid, i, page_count(page));
                SetPageUptodate(page);
-               SetPageDirty(page);
                unlock_page(page);
 
                ctx->ring_pages[i] = page;
index d3220d31d3cbf0e653898d15816f5895045c06d5..dcd9be32ac579451597dcf61e97b54631a69aa68 100644 (file)
@@ -1011,8 +1011,6 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
                bytes = min(bytes, working_bytes);
                kaddr = kmap_atomic(page_out);
                memcpy(kaddr + *pg_offset, buf + buf_offset, bytes);
-               if (*pg_index == (vcnt - 1) && *pg_offset == 0)
-                       memset(kaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
                kunmap_atomic(kaddr);
                flush_dcache_page(page_out);
 
@@ -1054,3 +1052,34 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
 
        return 1;
 }
+
+/*
+ * When uncompressing data, we need to make sure and zero any parts of
+ * the biovec that were not filled in by the decompression code.  pg_index
+ * and pg_offset indicate the last page and the last offset of that page
+ * that have been filled in.  This will zero everything remaining in the
+ * biovec.
+ */
+void btrfs_clear_biovec_end(struct bio_vec *bvec, int vcnt,
+                                  unsigned long pg_index,
+                                  unsigned long pg_offset)
+{
+       while (pg_index < vcnt) {
+               struct page *page = bvec[pg_index].bv_page;
+               unsigned long off = bvec[pg_index].bv_offset;
+               unsigned long len = bvec[pg_index].bv_len;
+
+               if (pg_offset < off)
+                       pg_offset = off;
+               if (pg_offset < off + len) {
+                       unsigned long bytes = off + len - pg_offset;
+                       char *kaddr;
+
+                       kaddr = kmap_atomic(page);
+                       memset(kaddr + pg_offset, 0, bytes);
+                       kunmap_atomic(kaddr);
+               }
+               pg_index++;
+               pg_offset = 0;
+       }
+}
index 0c803b4fbf93dc8062e644952abb7f36ff0e8504..d181f70caae01471ca80e181818a833b41f057de 100644 (file)
@@ -45,7 +45,9 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
                                  unsigned long nr_pages);
 int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
                                 int mirror_num, unsigned long bio_flags);
-
+void btrfs_clear_biovec_end(struct bio_vec *bvec, int vcnt,
+                                  unsigned long pg_index,
+                                  unsigned long pg_offset);
 struct btrfs_compress_op {
        struct list_head *(*alloc_workspace)(void);
 
index 19bc6162fb8e899cc51bd3d777fcbddf91589aa6..150822ee0a0b9f9668f071885c4f018b1c9f6bf3 100644 (file)
@@ -80,13 +80,6 @@ noinline void btrfs_clear_path_blocking(struct btrfs_path *p,
 {
        int i;
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-       /* lockdep really cares that we take all of these spinlocks
-        * in the right order.  If any of the locks in the path are not
-        * currently blocking, it is going to complain.  So, make really
-        * really sure by forcing the path to blocking before we clear
-        * the path blocking.
-        */
        if (held) {
                btrfs_set_lock_blocking_rw(held, held_rw);
                if (held_rw == BTRFS_WRITE_LOCK)
@@ -95,7 +88,6 @@ noinline void btrfs_clear_path_blocking(struct btrfs_path *p,
                        held_rw = BTRFS_READ_LOCK_BLOCKING;
        }
        btrfs_set_path_blocking(p);
-#endif
 
        for (i = BTRFS_MAX_LEVEL - 1; i >= 0; i--) {
                if (p->nodes[i] && p->locks[i]) {
@@ -107,10 +99,8 @@ noinline void btrfs_clear_path_blocking(struct btrfs_path *p,
                }
        }
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
        if (held)
                btrfs_clear_lock_blocking_rw(held, held_rw);
-#endif
 }
 
 /* this also releases the path */
@@ -2893,7 +2883,7 @@ cow_done:
                                        }
                                        p->locks[level] = BTRFS_WRITE_LOCK;
                                } else {
-                                       err = btrfs_try_tree_read_lock(b);
+                                       err = btrfs_tree_read_lock_atomic(b);
                                        if (!err) {
                                                btrfs_set_path_blocking(p);
                                                btrfs_tree_read_lock(b);
@@ -3025,7 +3015,7 @@ again:
                        }
 
                        level = btrfs_header_level(b);
-                       err = btrfs_try_tree_read_lock(b);
+                       err = btrfs_tree_read_lock_atomic(b);
                        if (!err) {
                                btrfs_set_path_blocking(p);
                                btrfs_tree_read_lock(b);
index 5665d2149249d1d83a260c74f21889e1d394a6c3..f8229ef1b46df098a3b04260c4f943db3e924d49 100644 (file)
@@ -127,6 +127,26 @@ again:
        atomic_inc(&eb->spinning_readers);
 }
 
+/*
+ * take a spinning read lock.
+ * returns 1 if we get the read lock and 0 if we don't
+ * this won't wait for blocking writers
+ */
+int btrfs_tree_read_lock_atomic(struct extent_buffer *eb)
+{
+       if (atomic_read(&eb->blocking_writers))
+               return 0;
+
+       read_lock(&eb->lock);
+       if (atomic_read(&eb->blocking_writers)) {
+               read_unlock(&eb->lock);
+               return 0;
+       }
+       atomic_inc(&eb->read_locks);
+       atomic_inc(&eb->spinning_readers);
+       return 1;
+}
+
 /*
  * returns 1 if we get the read lock and 0 if we don't
  * this won't wait for blocking writers
@@ -158,9 +178,7 @@ int btrfs_try_tree_write_lock(struct extent_buffer *eb)
            atomic_read(&eb->blocking_readers))
                return 0;
 
-       if (!write_trylock(&eb->lock))
-               return 0;
-
+       write_lock(&eb->lock);
        if (atomic_read(&eb->blocking_writers) ||
            atomic_read(&eb->blocking_readers)) {
                write_unlock(&eb->lock);
index b81e0e9a48941891681eef385d10d071f6cbe51b..c44a9d5f5362b0dcb1c525eca16b57aead8a58ae 100644 (file)
@@ -35,6 +35,8 @@ void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw);
 void btrfs_assert_tree_locked(struct extent_buffer *eb);
 int btrfs_try_tree_read_lock(struct extent_buffer *eb);
 int btrfs_try_tree_write_lock(struct extent_buffer *eb);
+int btrfs_tree_read_lock_atomic(struct extent_buffer *eb);
+
 
 static inline void btrfs_tree_unlock_rw(struct extent_buffer *eb, int rw)
 {
index 78285f30909edd09f19cc6eb48985d47eed3c565..617553cdb7d3b36b1b8ca6a87b28526c5a060b4d 100644 (file)
@@ -373,6 +373,8 @@ cont:
        }
 done:
        kunmap(pages_in[page_in_index]);
+       if (!ret)
+               btrfs_clear_biovec_end(bvec, vcnt, page_out_index, pg_offset);
        return ret;
 }
 
@@ -410,10 +412,23 @@ static int lzo_decompress(struct list_head *ws, unsigned char *data_in,
                goto out;
        }
 
+       /*
+        * the caller is already checking against PAGE_SIZE, but lets
+        * move this check closer to the memcpy/memset
+        */
+       destlen = min_t(unsigned long, destlen, PAGE_SIZE);
        bytes = min_t(unsigned long, destlen, out_len - start_byte);
 
        kaddr = kmap_atomic(dest_page);
        memcpy(kaddr, workspace->buf + start_byte, bytes);
+
+       /*
+        * btrfs_getblock is doing a zero on the tail of the page too,
+        * but this will cover anything missing from the decompressed
+        * data.
+        */
+       if (bytes < destlen)
+               memset(kaddr+bytes, 0, destlen-bytes);
        kunmap_atomic(kaddr);
 out:
        return ret;
index 759fa4e2de8fec28d3f6448456e1e12cec1add17..fb22fd8d8fb8fad73cb4d2b63d4d525da3eea876 100644 (file)
@@ -299,6 +299,8 @@ done:
        zlib_inflateEnd(&workspace->strm);
        if (data_in)
                kunmap(pages_in[page_in_index]);
+       if (!ret)
+               btrfs_clear_biovec_end(bvec, vcnt, page_out_index, pg_offset);
        return ret;
 }
 
@@ -310,10 +312,14 @@ static int zlib_decompress(struct list_head *ws, unsigned char *data_in,
        struct workspace *workspace = list_entry(ws, struct workspace, list);
        int ret = 0;
        int wbits = MAX_WBITS;
-       unsigned long bytes_left = destlen;
+       unsigned long bytes_left;
        unsigned long total_out = 0;
+       unsigned long pg_offset = 0;
        char *kaddr;
 
+       destlen = min_t(unsigned long, destlen, PAGE_SIZE);
+       bytes_left = destlen;
+
        workspace->strm.next_in = data_in;
        workspace->strm.avail_in = srclen;
        workspace->strm.total_in = 0;
@@ -341,7 +347,6 @@ static int zlib_decompress(struct list_head *ws, unsigned char *data_in,
                unsigned long buf_start;
                unsigned long buf_offset;
                unsigned long bytes;
-               unsigned long pg_offset = 0;
 
                ret = zlib_inflate(&workspace->strm, Z_NO_FLUSH);
                if (ret != Z_OK && ret != Z_STREAM_END)
@@ -384,6 +389,17 @@ next:
                ret = 0;
 
        zlib_inflateEnd(&workspace->strm);
+
+       /*
+        * this should only happen if zlib returned fewer bytes than we
+        * expected.  btrfs_get_block is responsible for zeroing from the
+        * end of the inline extent (destlen) to the end of the page
+        */
+       if (pg_offset < destlen) {
+               kaddr = kmap_atomic(dest_page);
+               memset(kaddr + pg_offset, 0, destlen - pg_offset);
+               kunmap_atomic(kaddr);
+       }
        return ret;
 }
 
index 3ffef7f4e5cdd9d00ca454130070f4619a8707d6..5bc72b07fde22bcbb00451c7522333e2aa273323 100644 (file)
@@ -778,6 +778,7 @@ restart:
                        struct dentry *parent = lock_parent(dentry);
                        if (likely(!dentry->d_lockref.count)) {
                                __dentry_kill(dentry);
+                               dput(parent);
                                goto restart;
                        }
                        if (parent)
index fe839b9151161544cd5a4f3243918b25e995b599..d67a16f2a45df8fcce56b9ff3ec56f334d951c9c 100644 (file)
@@ -170,27 +170,6 @@ struct iso9660_options{
        s32 sbsector;
 };
 
-/*
- * Compute the hash for the isofs name corresponding to the dentry.
- */
-static int
-isofs_hash_common(struct qstr *qstr, int ms)
-{
-       const char *name;
-       int len;
-
-       len = qstr->len;
-       name = qstr->name;
-       if (ms) {
-               while (len && name[len-1] == '.')
-                       len--;
-       }
-
-       qstr->hash = full_name_hash(name, len);
-
-       return 0;
-}
-
 /*
  * Compute the hash for the isofs name corresponding to the dentry.
  */
@@ -263,6 +242,27 @@ isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry,
 }
 
 #ifdef CONFIG_JOLIET
+/*
+ * Compute the hash for the isofs name corresponding to the dentry.
+ */
+static int
+isofs_hash_common(struct qstr *qstr, int ms)
+{
+       const char *name;
+       int len;
+
+       len = qstr->len;
+       name = qstr->name;
+       if (ms) {
+               while (len && name[len-1] == '.')
+                       len--;
+       }
+
+       qstr->hash = full_name_hash(name, len);
+
+       return 0;
+}
+
 static int
 isofs_hash_ms(const struct dentry *dentry, struct qstr *qstr)
 {
index ed2b1151b171f275b6a5ebeea1946860876fb391..7cbdf1b2e4abd7286b6033c66a9d999e735737c9 100644 (file)
@@ -774,8 +774,12 @@ static bool nfsd41_cb_get_slot(struct nfs4_client *clp, struct rpc_task *task)
 {
        if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) {
                rpc_sleep_on(&clp->cl_cb_waitq, task, NULL);
-               dprintk("%s slot is busy\n", __func__);
-               return false;
+               /* Race breaker */
+               if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) {
+                       dprintk("%s slot is busy\n", __func__);
+                       return false;
+               }
+               rpc_wake_up_queued_task(&clp->cl_cb_waitq, task);
        }
        return true;
 }
index 747f3b95bd11118aa477153fa97594127e2fbc1c..33a46a8dfaf73aaa65ecec7b4603b86ea4e49d83 100644 (file)
@@ -335,12 +335,15 @@ void              nfsd_lockd_shutdown(void);
        (NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT)
 
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
-#define NFSD4_2_SUPPORTED_ATTRS_WORD2 \
-       (NFSD4_1_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SECURITY_LABEL)
+#define NFSD4_2_SECURITY_ATTRS         FATTR4_WORD2_SECURITY_LABEL
 #else
-#define NFSD4_2_SUPPORTED_ATTRS_WORD2 0
+#define NFSD4_2_SECURITY_ATTRS         0
 #endif
 
+#define NFSD4_2_SUPPORTED_ATTRS_WORD2 \
+       (NFSD4_1_SUPPORTED_ATTRS_WORD2 | \
+       NFSD4_2_SECURITY_ATTRS)
+
 static inline u32 nfsd_suppattrs0(u32 minorversion)
 {
        return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0
index e60125976873b23314035580041ab73ef2f147ac..34355818a2e03460759b144f8f9c284d5a810423 100644 (file)
@@ -1,4 +1,4 @@
-config OVERLAYFS_FS
+config OVERLAY_FS
        tristate "Overlay filesystem support"
        help
          An overlay filesystem combines two filesystems - an 'upper' filesystem
index 8f91889480d0515011c3ebe64beef3660ea82b28..900daed3e91d28f1901c78cab4e9c2fdddf50043 100644 (file)
@@ -2,6 +2,6 @@
 # Makefile for the overlay filesystem.
 #
 
-obj-$(CONFIG_OVERLAYFS_FS) += overlayfs.o
+obj-$(CONFIG_OVERLAY_FS) += overlay.o
 
-overlayfs-objs := super.o inode.o dir.o readdir.o copy_up.o
+overlay-objs := super.o inode.o dir.o readdir.o copy_up.o
index 15cd91ad9940db5f130883120cf3b9606efe0705..8ffc4b980f1b68641c17a7bfb67979f205c658b5 100644 (file)
@@ -284,8 +284,7 @@ out:
        return ERR_PTR(err);
 }
 
-static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry,
-                                               enum ovl_path_type type)
+static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry)
 {
        int err;
        struct dentry *ret = NULL;
@@ -294,8 +293,17 @@ static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry,
        err = ovl_check_empty_dir(dentry, &list);
        if (err)
                ret = ERR_PTR(err);
-       else if (type == OVL_PATH_MERGE)
-               ret = ovl_clear_empty(dentry, &list);
+       else {
+               /*
+                * If no upperdentry then skip clearing whiteouts.
+                *
+                * Can race with copy-up, since we don't hold the upperdir
+                * mutex.  Doesn't matter, since copy-up can't create a
+                * non-empty directory from an empty one.
+                */
+               if (ovl_dentry_upper(dentry))
+                       ret = ovl_clear_empty(dentry, &list);
+       }
 
        ovl_cache_free(&list);
 
@@ -487,8 +495,7 @@ out:
        return err;
 }
 
-static int ovl_remove_and_whiteout(struct dentry *dentry,
-                                  enum ovl_path_type type, bool is_dir)
+static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
 {
        struct dentry *workdir = ovl_workdir(dentry);
        struct inode *wdir = workdir->d_inode;
@@ -500,7 +507,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry,
        int err;
 
        if (is_dir) {
-               opaquedir = ovl_check_empty_and_clear(dentry, type);
+               opaquedir = ovl_check_empty_and_clear(dentry);
                err = PTR_ERR(opaquedir);
                if (IS_ERR(opaquedir))
                        goto out;
@@ -515,9 +522,10 @@ static int ovl_remove_and_whiteout(struct dentry *dentry,
        if (IS_ERR(whiteout))
                goto out_unlock;
 
-       if (type == OVL_PATH_LOWER) {
+       upper = ovl_dentry_upper(dentry);
+       if (!upper) {
                upper = lookup_one_len(dentry->d_name.name, upperdir,
-                                          dentry->d_name.len);
+                                      dentry->d_name.len);
                err = PTR_ERR(upper);
                if (IS_ERR(upper))
                        goto kill_whiteout;
@@ -529,7 +537,6 @@ static int ovl_remove_and_whiteout(struct dentry *dentry,
        } else {
                int flags = 0;
 
-               upper = ovl_dentry_upper(dentry);
                if (opaquedir)
                        upper = opaquedir;
                err = -ESTALE;
@@ -648,7 +655,7 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
                cap_raise(override_cred->cap_effective, CAP_CHOWN);
                old_cred = override_creds(override_cred);
 
-               err = ovl_remove_and_whiteout(dentry, type, is_dir);
+               err = ovl_remove_and_whiteout(dentry, is_dir);
 
                revert_creds(old_cred);
                put_cred(override_cred);
@@ -781,7 +788,7 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
        }
 
        if (overwrite && (new_type == OVL_PATH_LOWER || new_type == OVL_PATH_MERGE) && new_is_dir) {
-               opaquedir = ovl_check_empty_and_clear(new, new_type);
+               opaquedir = ovl_check_empty_and_clear(new);
                err = PTR_ERR(opaquedir);
                if (IS_ERR(opaquedir)) {
                        opaquedir = NULL;
index af2d18c9fcee19af345aa66c5bcf31407e316f21..07d74b24913bdee757377d103427883fb7d12e70 100644 (file)
@@ -235,26 +235,36 @@ out:
        return err;
 }
 
+static bool ovl_need_xattr_filter(struct dentry *dentry,
+                                 enum ovl_path_type type)
+{
+       return type == OVL_PATH_UPPER && S_ISDIR(dentry->d_inode->i_mode);
+}
+
 ssize_t ovl_getxattr(struct dentry *dentry, const char *name,
                     void *value, size_t size)
 {
-       if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE &&
-           ovl_is_private_xattr(name))
+       struct path realpath;
+       enum ovl_path_type type = ovl_path_real(dentry, &realpath);
+
+       if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name))
                return -ENODATA;
 
-       return vfs_getxattr(ovl_dentry_real(dentry), name, value, size);
+       return vfs_getxattr(realpath.dentry, name, value, size);
 }
 
 ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
 {
+       struct path realpath;
+       enum ovl_path_type type = ovl_path_real(dentry, &realpath);
        ssize_t res;
        int off;
 
-       res = vfs_listxattr(ovl_dentry_real(dentry), list, size);
+       res = vfs_listxattr(realpath.dentry, list, size);
        if (res <= 0 || size == 0)
                return res;
 
-       if (ovl_path_type(dentry->d_parent) != OVL_PATH_MERGE)
+       if (!ovl_need_xattr_filter(dentry, type))
                return res;
 
        /* filter out private xattrs */
@@ -279,17 +289,16 @@ int ovl_removexattr(struct dentry *dentry, const char *name)
 {
        int err;
        struct path realpath;
-       enum ovl_path_type type;
+       enum ovl_path_type type = ovl_path_real(dentry, &realpath);
 
        err = ovl_want_write(dentry);
        if (err)
                goto out;
 
-       if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE &&
-           ovl_is_private_xattr(name))
+       err = -ENODATA;
+       if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name))
                goto out_drop_write;
 
-       type = ovl_path_real(dentry, &realpath);
        if (type == OVL_PATH_LOWER) {
                err = vfs_getxattr(realpath.dentry, name, NULL, 0);
                if (err < 0)
index 2a7ef4f8e2a6c37e033b771413fc66f75b567556..ab1e3dcbed9523d05b3bf4d73a5b685532e0acaa 100644 (file)
@@ -274,11 +274,11 @@ static int ovl_dir_mark_whiteouts(struct dentry *dir,
        return 0;
 }
 
-static inline int ovl_dir_read_merged(struct path *upperpath,
-                                     struct path *lowerpath,
-                                     struct list_head *list)
+static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
 {
        int err;
+       struct path lowerpath;
+       struct path upperpath;
        struct ovl_readdir_data rdd = {
                .ctx.actor = ovl_fill_merge,
                .list = list,
@@ -286,25 +286,28 @@ static inline int ovl_dir_read_merged(struct path *upperpath,
                .is_merge = false,
        };
 
-       if (upperpath->dentry) {
-               err = ovl_dir_read(upperpath, &rdd);
+       ovl_path_lower(dentry, &lowerpath);
+       ovl_path_upper(dentry, &upperpath);
+
+       if (upperpath.dentry) {
+               err = ovl_dir_read(&upperpath, &rdd);
                if (err)
                        goto out;
 
-               if (lowerpath->dentry) {
-                       err = ovl_dir_mark_whiteouts(upperpath->dentry, &rdd);
+               if (lowerpath.dentry) {
+                       err = ovl_dir_mark_whiteouts(upperpath.dentry, &rdd);
                        if (err)
                                goto out;
                }
        }
-       if (lowerpath->dentry) {
+       if (lowerpath.dentry) {
                /*
                 * Insert lowerpath entries before upperpath ones, this allows
                 * offsets to be reasonably constant
                 */
                list_add(&rdd.middle, rdd.list);
                rdd.is_merge = true;
-               err = ovl_dir_read(lowerpath, &rdd);
+               err = ovl_dir_read(&lowerpath, &rdd);
                list_del(&rdd.middle);
        }
 out:
@@ -329,8 +332,6 @@ static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos)
 static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)
 {
        int res;
-       struct path lowerpath;
-       struct path upperpath;
        struct ovl_dir_cache *cache;
 
        cache = ovl_dir_cache(dentry);
@@ -347,10 +348,7 @@ static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)
        cache->refcount = 1;
        INIT_LIST_HEAD(&cache->entries);
 
-       ovl_path_lower(dentry, &lowerpath);
-       ovl_path_upper(dentry, &upperpath);
-
-       res = ovl_dir_read_merged(&upperpath, &lowerpath, &cache->entries);
+       res = ovl_dir_read_merged(dentry, &cache->entries);
        if (res) {
                ovl_cache_free(&cache->entries);
                kfree(cache);
@@ -452,10 +450,10 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
        /*
         * Need to check if we started out being a lower dir, but got copied up
         */
-       if (!od->is_upper && ovl_path_type(dentry) == OVL_PATH_MERGE) {
+       if (!od->is_upper && ovl_path_type(dentry) != OVL_PATH_LOWER) {
                struct inode *inode = file_inode(file);
 
-               realfile =lockless_dereference(od->upperfile);
+               realfile = lockless_dereference(od->upperfile);
                if (!realfile) {
                        struct path upperpath;
 
@@ -538,14 +536,9 @@ const struct file_operations ovl_dir_operations = {
 int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list)
 {
        int err;
-       struct path lowerpath;
-       struct path upperpath;
        struct ovl_cache_entry *p;
 
-       ovl_path_upper(dentry, &upperpath);
-       ovl_path_lower(dentry, &lowerpath);
-
-       err = ovl_dir_read_merged(&upperpath, &lowerpath, list);
+       err = ovl_dir_read_merged(dentry, list);
        if (err)
                return err;
 
index 08b704cebfc4f8819944e09b05f5f7de35659b92..f16d318b71f8bbe4e77f8a3214e616101848e49c 100644 (file)
@@ -24,7 +24,7 @@ MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
 MODULE_DESCRIPTION("Overlay filesystem");
 MODULE_LICENSE("GPL");
 
-#define OVERLAYFS_SUPER_MAGIC 0x794c764f
+#define OVERLAYFS_SUPER_MAGIC 0x794c7630
 
 struct ovl_config {
        char *lowerdir;
@@ -84,12 +84,7 @@ enum ovl_path_type ovl_path_type(struct dentry *dentry)
 
 static struct dentry *ovl_upperdentry_dereference(struct ovl_entry *oe)
 {
-       struct dentry *upperdentry = ACCESS_ONCE(oe->__upperdentry);
-       /*
-        * Make sure to order reads to upperdentry wrt ovl_dentry_update()
-        */
-       smp_read_barrier_depends();
-       return upperdentry;
+       return lockless_dereference(oe->__upperdentry);
 }
 
 void ovl_path_upper(struct dentry *dentry, struct path *path)
@@ -462,11 +457,34 @@ static const match_table_t ovl_tokens = {
        {OPT_ERR,                       NULL}
 };
 
+static char *ovl_next_opt(char **s)
+{
+       char *sbegin = *s;
+       char *p;
+
+       if (sbegin == NULL)
+               return NULL;
+
+       for (p = sbegin; *p; p++) {
+               if (*p == '\\') {
+                       p++;
+                       if (!*p)
+                               break;
+               } else if (*p == ',') {
+                       *p = '\0';
+                       *s = p + 1;
+                       return sbegin;
+               }
+       }
+       *s = NULL;
+       return sbegin;
+}
+
 static int ovl_parse_opt(char *opt, struct ovl_config *config)
 {
        char *p;
 
-       while ((p = strsep(&opt, ",")) != NULL) {
+       while ((p = ovl_next_opt(&opt)) != NULL) {
                int token;
                substring_t args[MAX_OPT_ARGS];
 
@@ -554,15 +572,34 @@ out_dput:
        goto out_unlock;
 }
 
+static void ovl_unescape(char *s)
+{
+       char *d = s;
+
+       for (;; s++, d++) {
+               if (*s == '\\')
+                       s++;
+               *d = *s;
+               if (!*s)
+                       break;
+       }
+}
+
 static int ovl_mount_dir(const char *name, struct path *path)
 {
        int err;
+       char *tmp = kstrdup(name, GFP_KERNEL);
+
+       if (!tmp)
+               return -ENOMEM;
 
-       err = kern_path(name, LOOKUP_FOLLOW, path);
+       ovl_unescape(tmp);
+       err = kern_path(tmp, LOOKUP_FOLLOW, path);
        if (err) {
-               pr_err("overlayfs: failed to resolve '%s': %i\n", name, err);
+               pr_err("overlayfs: failed to resolve '%s': %i\n", tmp, err);
                err = -EINVAL;
        }
+       kfree(tmp);
        return err;
 }
 
@@ -776,11 +813,11 @@ static struct dentry *ovl_mount(struct file_system_type *fs_type, int flags,
 
 static struct file_system_type ovl_fs_type = {
        .owner          = THIS_MODULE,
-       .name           = "overlayfs",
+       .name           = "overlay",
        .mount          = ovl_mount,
        .kill_sb        = kill_anon_super,
 };
-MODULE_ALIAS_FS("overlayfs");
+MODULE_ALIAS_FS("overlay");
 
 static int __init ovl_init(void)
 {
index d7ebd7b207e39232ba58c1eae2fcccf6ae5310ae..8ba35c622e2202a889a3a06706bdc93e035fb841 100644 (file)
@@ -809,7 +809,7 @@ struct drm_device {
        struct drm_local_map *agp_buffer_map;
        unsigned int agp_buffer_token;
 
-        struct drm_mode_config mode_config;    /**< Current mode config */
+       struct drm_mode_config mode_config;     /**< Current mode config */
 
        /** \name GEM information */
        /*@{ */
@@ -986,7 +986,7 @@ extern void drm_gem_dmabuf_release(struct dma_buf *dma_buf);
 
 extern int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
                                            dma_addr_t *addrs, int max_pages);
-extern struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages);
+extern struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages);
 extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg);
 
 
@@ -1028,10 +1028,25 @@ void drm_pci_agp_destroy(struct drm_device *dev);
 
 extern int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver);
 extern void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver);
+#ifdef CONFIG_PCI
 extern int drm_get_pci_dev(struct pci_dev *pdev,
                           const struct pci_device_id *ent,
                           struct drm_driver *driver);
 extern int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master);
+#else
+static inline int drm_get_pci_dev(struct pci_dev *pdev,
+                                 const struct pci_device_id *ent,
+                                 struct drm_driver *driver)
+{
+       return -ENOSYS;
+}
+
+static inline int drm_pci_set_busid(struct drm_device *dev,
+                                   struct drm_master *master)
+{
+       return -ENOSYS;
+}
+#endif
 
 #define DRM_PCIE_SPEED_25 1
 #define DRM_PCIE_SPEED_50 2
index 9d919168bc11a002fde4e2417dd630eb31f4ad69..ad2229574dd9456e9ba28a4c8e16f2492963b3b3 100644 (file)
@@ -28,6 +28,8 @@
 #ifndef DRM_ATOMIC_H_
 #define DRM_ATOMIC_H_
 
+#include <drm/drm_crtc.h>
+
 struct drm_atomic_state * __must_check
 drm_atomic_state_alloc(struct drm_device *dev);
 void drm_atomic_state_clear(struct drm_atomic_state *state);
@@ -44,8 +46,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
                               struct drm_connector *connector);
 
 int __must_check
-drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
-                             struct drm_crtc *crtc);
+drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state,
+                             struct drm_plane *plane, struct drm_crtc *crtc);
 void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
                                 struct drm_framebuffer *fb);
 int __must_check
index 67e3c4645ae0b3aadf329fa270aede0dc4e0a022..f956b413311e15eed5653b348708468d26197ed9 100644 (file)
 #ifndef DRM_ATOMIC_HELPER_H_
 #define DRM_ATOMIC_HELPER_H_
 
+#include <drm/drm_crtc.h>
+
 int drm_atomic_helper_check(struct drm_device *dev,
                            struct drm_atomic_state *state);
 int drm_atomic_helper_commit(struct drm_device *dev,
                             struct drm_atomic_state *state,
                             bool async);
 
+void drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
+                                       struct drm_atomic_state *old_state);
+
 void drm_atomic_helper_commit_pre_planes(struct drm_device *dev,
                                         struct drm_atomic_state *state);
 void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
@@ -93,5 +98,29 @@ drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector);
 void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
                                          struct drm_connector_state *state);
 
+/**
+ * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
+ * @plane: the loop cursor
+ * @crtc:  the crtc whose planes are iterated
+ *
+ * This iterates over the current state, useful (for example) when applying
+ * atomic state after it has been checked and swapped.  To iterate over the
+ * planes which *will* be attached (for ->atomic_check()) see
+ * drm_crtc_for_each_pending_plane()
+ */
+#define drm_atomic_crtc_for_each_plane(plane, crtc) \
+       drm_for_each_plane_mask(plane, (crtc)->dev, (crtc)->state->plane_mask)
+
+/**
+ * drm_crtc_atomic_state_for_each_plane - iterate over attached planes in new state
+ * @plane: the loop cursor
+ * @crtc_state: the incoming crtc-state
+ *
+ * Similar to drm_crtc_for_each_plane(), but iterates the planes that will be
+ * attached if the specified state is applied.  Useful during (for example)
+ * ->atomic_check() operations, to validate the incoming state
+ */
+#define drm_atomic_crtc_state_for_each_plane(plane, crtc_state) \
+       drm_for_each_plane_mask(plane, (crtc_state)->state->dev, (crtc_state)->plane_mask)
 
 #endif /* DRM_ATOMIC_HELPER_H_ */
index bc1cc3ce05c44fef38c6bfb0802dd08c6c592fa3..dd2c16e4333312194151cf47b946507871d2027d 100644 (file)
@@ -197,7 +197,7 @@ struct drm_framebuffer {
 struct drm_property_blob {
        struct drm_mode_object base;
        struct list_head head;
-       unsigned int length;
+       size_t length;
        unsigned char data[];
 };
 
@@ -216,7 +216,7 @@ struct drm_property {
        uint64_t *values;
        struct drm_device *dev;
 
-       struct list_head enum_blob_list;
+       struct list_head enum_list;
 };
 
 struct drm_crtc;
@@ -231,6 +231,7 @@ struct drm_atomic_state;
  * struct drm_crtc_state - mutable CRTC state
  * @enable: whether the CRTC should be enabled, gates all other state
  * @mode_changed: for use by helpers and drivers when computing state updates
+ * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
  * @last_vblank_count: for helpers and drivers to capture the vblank of the
  *     update to ensure framebuffer cleanup isn't done too early
  * @planes_changed: for use by helpers and drivers when computing state updates
@@ -247,6 +248,13 @@ struct drm_crtc_state {
        bool planes_changed : 1;
        bool mode_changed : 1;
 
+       /* attached planes bitmask:
+        * WARNING: transitional helpers do not maintain plane_mask so
+        * drivers not converted over to atomic helpers should not rely
+        * on plane_mask being accurate!
+        */
+       u32 plane_mask;
+
        /* last_vblank_count: for vblank waits before cleanup */
        u32 last_vblank_count;
 
@@ -438,7 +446,7 @@ struct drm_crtc {
  * @state: backpointer to global drm_atomic_state
  */
 struct drm_connector_state {
-       struct drm_crtc *crtc;
+       struct drm_crtc *crtc;  /* do not write directly, use drm_atomic_set_crtc_for_connector() */
 
        struct drm_encoder *best_encoder;
 
@@ -673,8 +681,8 @@ struct drm_connector {
  * @state: backpointer to global drm_atomic_state
  */
 struct drm_plane_state {
-       struct drm_crtc *crtc;
-       struct drm_framebuffer *fb;
+       struct drm_crtc *crtc;   /* do not write directly, use drm_atomic_set_crtc_for_plane() */
+       struct drm_framebuffer *fb;  /* do not write directly, use drm_atomic_set_fb_for_plane() */
        struct fence *fence;
 
        /* Signed dest location allows it to be partially off screen */
@@ -751,6 +759,8 @@ struct drm_plane {
        struct drm_device *dev;
        struct list_head head;
 
+       struct drm_modeset_lock mutex;
+
        struct drm_mode_object base;
 
        uint32_t possible_crtcs;
@@ -823,6 +833,7 @@ struct drm_bridge {
  * @plane_states: pointer to array of plane states pointers
  * @crtcs: pointer to array of CRTC pointers
  * @crtc_states: pointer to array of CRTC states pointers
+ * @num_connector: size of the @connectors and @connector_states arrays
  * @connectors: pointer to array of connector pointers
  * @connector_states: pointer to array of connector states pointers
  * @acquire_ctx: acquire context for this atomic modeset state update
@@ -834,6 +845,7 @@ struct drm_atomic_state {
        struct drm_plane_state **plane_states;
        struct drm_crtc **crtcs;
        struct drm_crtc_state **crtc_states;
+       int num_connector;
        struct drm_connector **connectors;
        struct drm_connector_state **connector_states;
 
@@ -1036,6 +1048,10 @@ struct drm_mode_config {
        struct drm_property *aspect_ratio_property;
        struct drm_property *dirty_info_property;
 
+       /* properties for virtual machine layout */
+       struct drm_property *suggested_x_property;
+       struct drm_property *suggested_y_property;
+
        /* dumb ioctl parameters */
        uint32_t preferred_depth, prefer_shadow;
 
@@ -1046,6 +1062,19 @@ struct drm_mode_config {
        uint32_t cursor_width, cursor_height;
 };
 
+/**
+ * drm_for_each_plane_mask - iterate over planes specified by bitmask
+ * @plane: the loop cursor
+ * @dev: the DRM device
+ * @plane_mask: bitmask of plane indices
+ *
+ * Iterate over all planes specified by bitmask.
+ */
+#define drm_for_each_plane_mask(plane, dev, plane_mask) \
+       list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \
+               if ((plane_mask) & (1 << drm_plane_index(plane)))
+
+
 #define obj_to_crtc(x) container_of(x, struct drm_crtc, base)
 #define obj_to_connector(x) container_of(x, struct drm_connector, base)
 #define obj_to_encoder(x) container_of(x, struct drm_encoder, base)
@@ -1160,9 +1189,9 @@ extern void drm_mode_config_reset(struct drm_device *dev);
 extern void drm_mode_config_cleanup(struct drm_device *dev);
 
 extern int drm_mode_connector_set_path_property(struct drm_connector *connector,
-                                               char *path);
+                                               const char *path);
 extern int drm_mode_connector_update_edid_property(struct drm_connector *connector,
-                                               struct edid *edid);
+                                                  const struct edid *edid);
 
 static inline bool drm_property_type_is(struct drm_property *property,
                uint32_t type)
@@ -1223,11 +1252,13 @@ extern void drm_property_destroy(struct drm_device *dev, struct drm_property *pr
 extern int drm_property_add_enum(struct drm_property *property, int index,
                                 uint64_t value, const char *name);
 extern int drm_mode_create_dvi_i_properties(struct drm_device *dev);
-extern int drm_mode_create_tv_properties(struct drm_device *dev, int num_formats,
-                                    char *formats[]);
+extern int drm_mode_create_tv_properties(struct drm_device *dev,
+                                        unsigned int num_modes,
+                                        char *modes[]);
 extern int drm_mode_create_scaling_mode_property(struct drm_device *dev);
 extern int drm_mode_create_aspect_ratio_property(struct drm_device *dev);
 extern int drm_mode_create_dirty_info_property(struct drm_device *dev);
+extern int drm_mode_create_suggested_offset_properties(struct drm_device *dev);
 
 extern int drm_mode_connector_attach_encoder(struct drm_connector *connector,
                                             struct drm_encoder *encoder);
index 05e85ee10e74e8a70b5b0c46a621f5e203d3d822..cec6383bbdb8afbdd092ff0a869446070a37adfe 100644 (file)
@@ -371,7 +371,7 @@ struct drm_dp_sideband_msg_tx {
 struct drm_dp_mst_topology_mgr;
 struct drm_dp_mst_topology_cbs {
        /* create a connector for a port */
-       struct drm_connector *(*add_connector)(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, char *path);
+       struct drm_connector *(*add_connector)(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, const char *path);
        void (*destroy_connector)(struct drm_dp_mst_topology_mgr *mgr,
                                  struct drm_connector *connector);
        void (*hotplug)(struct drm_dp_mst_topology_mgr *mgr);
index c2f1bfa22010f644d7ddf5f75b3024162143baee..d59240ffb1f7cc9f14b41a23b3cd9ba099a959c8 100644 (file)
@@ -381,4 +381,9 @@ static inline int drm_eld_size(const uint8_t *eld)
        return DRM_ELD_HEADER_BLOCK_SIZE + eld[DRM_ELD_BASELINE_ELD_LEN] * 4;
 }
 
+struct edid *drm_do_get_edid(struct drm_connector *connector,
+       int (*get_edid_block)(void *data, u8 *buf, unsigned int block,
+                             size_t len),
+       void *data);
+
 #endif /* __DRM_EDID_H__ */
index 9eed34dcd6afea74a8438f5571552cd472191a45..d387cf06ae05676667cd91afc37f61d57ae6c749 100644 (file)
@@ -25,6 +25,7 @@
 #define DRM_FLIP_WORK_H
 
 #include <linux/kfifo.h>
+#include <linux/spinlock.h>
 #include <linux/workqueue.h>
 
 /**
@@ -32,9 +33,9 @@
  *
  * Util to queue up work to run from work-queue context after flip/vblank.
  * Typically this can be used to defer unref of framebuffer's, cursor
- * bo's, etc until after vblank.  The APIs are all safe (and lockless)
- * for up to one producer and once consumer at a time.  The single-consumer
- * aspect is ensured by committing the queued work to a single work-queue.
+ * bo's, etc until after vblank.  The APIs are all thread-safe.
+ * Moreover, drm_flip_work_queue_task and drm_flip_work_queue can be called
+ * in atomic context.
  */
 
 struct drm_flip_work;
@@ -50,27 +51,41 @@ struct drm_flip_work;
  */
 typedef void (*drm_flip_func_t)(struct drm_flip_work *work, void *val);
 
+/**
+ * struct drm_flip_task - flip work task
+ * @node: list entry element
+ * @data: data to pass to work->func
+ */
+struct drm_flip_task {
+       struct list_head node;
+       void *data;
+};
+
 /**
  * struct drm_flip_work - flip work queue
  * @name: debug name
- * @pending: number of queued but not committed items
- * @count: number of committed items
  * @func: callback fxn called for each committed item
  * @worker: worker which calls @func
- * @fifo: queue of committed items
+ * @queued: queued tasks
+ * @commited: commited tasks
+ * @lock: lock to access queued and commited lists
  */
 struct drm_flip_work {
        const char *name;
-       atomic_t pending, count;
        drm_flip_func_t func;
        struct work_struct worker;
-       DECLARE_KFIFO_PTR(fifo, void *);
+       struct list_head queued;
+       struct list_head commited;
+       spinlock_t lock;
 };
 
+struct drm_flip_task *drm_flip_work_allocate_task(void *data, gfp_t flags);
+void drm_flip_work_queue_task(struct drm_flip_work *work,
+                             struct drm_flip_task *task);
 void drm_flip_work_queue(struct drm_flip_work *work, void *val);
 void drm_flip_work_commit(struct drm_flip_work *work,
                struct workqueue_struct *wq);
-int drm_flip_work_init(struct drm_flip_work *work, int size,
+void drm_flip_work_init(struct drm_flip_work *work,
                const char *name, drm_flip_func_t func);
 void drm_flip_work_cleanup(struct drm_flip_work *work);
 
index 1e6ae1458f7ab98ef42cd66ef9834cef8f276718..780511a459c01e3012efbfe2912ee27dc5996971 100644 (file)
@@ -119,6 +119,13 @@ struct drm_gem_object {
         * simply leave it as NULL.
         */
        struct dma_buf_attachment *import_attach;
+
+       /**
+        * dumb - created as dumb buffer
+        * Whether the gem object was created using the dumb buffer interface
+        * as such it may not be used for GPU rendering.
+        */
+       bool dumb;
 };
 
 void drm_gem_object_release(struct drm_gem_object *obj);
index 2ff35f3de9c5b9520587daca98f2c4d67b17bab4..acd6af8a8e675b5b58856651f18f788257bcc868 100644 (file)
@@ -4,6 +4,13 @@
 #include <drm/drmP.h>
 #include <drm/drm_gem.h>
 
+/**
+ * struct drm_gem_cma_object - GEM object backed by CMA memory allocations
+ * @base: base GEM object
+ * @paddr: physical address of the backing memory
+ * @sgt: scatter/gather table for imported PRIME buffers
+ * @vaddr: kernel virtual address of the backing memory
+ */
 struct drm_gem_cma_object {
        struct drm_gem_object base;
        dma_addr_t paddr;
@@ -19,23 +26,30 @@ to_drm_gem_cma_obj(struct drm_gem_object *gem_obj)
        return container_of(gem_obj, struct drm_gem_cma_object, base);
 }
 
-/* free gem object. */
+/* free GEM object */
 void drm_gem_cma_free_object(struct drm_gem_object *gem_obj);
 
-/* create memory region for drm framebuffer. */
+/* create memory region for DRM framebuffer */
+int drm_gem_cma_dumb_create_internal(struct drm_file *file_priv,
+                                    struct drm_device *drm,
+                                    struct drm_mode_create_dumb *args);
+
+/* create memory region for DRM framebuffer */
 int drm_gem_cma_dumb_create(struct drm_file *file_priv,
-               struct drm_device *drm, struct drm_mode_create_dumb *args);
+                           struct drm_device *drm,
+                           struct drm_mode_create_dumb *args);
 
-/* map memory region for drm framebuffer to user space. */
+/* map memory region for DRM framebuffer to user space */
 int drm_gem_cma_dumb_map_offset(struct drm_file *file_priv,
-               struct drm_device *drm, uint32_t handle, uint64_t *offset);
+                               struct drm_device *drm, u32 handle,
+                               u64 *offset);
 
-/* set vm_flags and we can change the vm attribute to other one at here. */
+/* set vm_flags and we can change the VM attribute to other one at here */
 int drm_gem_cma_mmap(struct file *filp, struct vm_area_struct *vma);
 
-/* allocate physical memory. */
+/* allocate physical memory */
 struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm,
-               unsigned int size);
+                                             size_t size);
 
 extern const struct vm_operations_struct drm_gem_cma_vm_ops;
 
index 8569dc5a1026a2a986ca5d15bd7e9575dd19723d..f1d8d0dbb4f162f9ea1c90dda44beedf14e4c175 100644 (file)
@@ -26,6 +26,7 @@ struct mipi_dsi_device;
  * struct mipi_dsi_msg - read/write DSI buffer
  * @channel: virtual channel id
  * @type: payload data type
+ * @flags: flags controlling this message transmission
  * @tx_len: length of @tx_buf
  * @tx_buf: data to be written
  * @rx_len: length of @rx_buf
@@ -43,12 +44,44 @@ struct mipi_dsi_msg {
        void *rx_buf;
 };
 
+bool mipi_dsi_packet_format_is_short(u8 type);
+bool mipi_dsi_packet_format_is_long(u8 type);
+
+/**
+ * struct mipi_dsi_packet - represents a MIPI DSI packet in protocol format
+ * @size: size (in bytes) of the packet
+ * @header: the four bytes that make up the header (Data ID, Word Count or
+ *     Packet Data, and ECC)
+ * @payload_length: number of bytes in the payload
+ * @payload: a pointer to a buffer containing the payload, if any
+ */
+struct mipi_dsi_packet {
+       size_t size;
+       u8 header[4];
+       size_t payload_length;
+       const u8 *payload;
+};
+
+int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
+                          const struct mipi_dsi_msg *msg);
+
 /**
  * struct mipi_dsi_host_ops - DSI bus operations
  * @attach: attach DSI device to DSI host
  * @detach: detach DSI device from DSI host
- * @transfer: send and/or receive DSI packet, return number of received bytes,
- *           or error
+ * @transfer: transmit a DSI packet
+ *
+ * DSI packets transmitted by .transfer() are passed in as mipi_dsi_msg
+ * structures. This structure contains information about the type of packet
+ * being transmitted as well as the transmit and receive buffers. When an
+ * error is encountered during transmission, this function will return a
+ * negative error code. On success it shall return the number of bytes
+ * transmitted for write packets or the number of bytes received for read
+ * packets.
+ *
+ * Note that typically DSI packet transmission is atomic, so the .transfer()
+ * function will seldomly return anything other than the number of bytes
+ * contained in the transmit buffer on success.
  */
 struct mipi_dsi_host_ops {
        int (*attach)(struct mipi_dsi_host *host,
@@ -56,7 +89,7 @@ struct mipi_dsi_host_ops {
        int (*detach)(struct mipi_dsi_host *host,
                      struct mipi_dsi_device *dsi);
        ssize_t (*transfer)(struct mipi_dsi_host *host,
-                           struct mipi_dsi_msg *msg);
+                           const struct mipi_dsi_msg *msg);
 };
 
 /**
@@ -130,12 +163,57 @@ static inline struct mipi_dsi_device *to_mipi_dsi_device(struct device *dev)
        return container_of(dev, struct mipi_dsi_device, dev);
 }
 
+struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np);
 int mipi_dsi_attach(struct mipi_dsi_device *dsi);
 int mipi_dsi_detach(struct mipi_dsi_device *dsi);
-ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data,
-                           size_t len);
+int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
+                                           u16 value);
+
+ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload,
+                              size_t size);
+ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
+                             size_t num_params, void *data, size_t size);
+
+/**
+ * enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode
+ * @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
+ *    information only
+ * @MIPI_DSI_DCS_TEAR_MODE_VHBLANK : the TE output line consists of both
+ *    V-Blanking and H-Blanking information
+ */
+enum mipi_dsi_dcs_tear_mode {
+       MIPI_DSI_DCS_TEAR_MODE_VBLANK,
+       MIPI_DSI_DCS_TEAR_MODE_VHBLANK,
+};
+
+#define MIPI_DSI_DCS_POWER_MODE_DISPLAY (1 << 2)
+#define MIPI_DSI_DCS_POWER_MODE_NORMAL  (1 << 3)
+#define MIPI_DSI_DCS_POWER_MODE_SLEEP   (1 << 4)
+#define MIPI_DSI_DCS_POWER_MODE_PARTIAL (1 << 5)
+#define MIPI_DSI_DCS_POWER_MODE_IDLE    (1 << 6)
+
+ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi,
+                                 const void *data, size_t len);
+ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
+                          const void *data, size_t len);
 ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data,
                          size_t len);
+int mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi);
+int mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi);
+int mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode);
+int mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format);
+int mipi_dsi_dcs_enter_sleep_mode(struct mipi_dsi_device *dsi);
+int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi);
+int mipi_dsi_dcs_set_display_off(struct mipi_dsi_device *dsi);
+int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi);
+int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start,
+                                   u16 end);
+int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start,
+                                 u16 end);
+int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi);
+int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi,
+                            enum mipi_dsi_dcs_tear_mode mode);
+int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format);
 
 /**
  * struct mipi_dsi_driver - DSI driver
@@ -167,9 +245,13 @@ static inline void mipi_dsi_set_drvdata(struct mipi_dsi_device *dsi, void *data)
        dev_set_drvdata(&dsi->dev, data);
 }
 
-int mipi_dsi_driver_register(struct mipi_dsi_driver *driver);
+int mipi_dsi_driver_register_full(struct mipi_dsi_driver *driver,
+                                 struct module *owner);
 void mipi_dsi_driver_unregister(struct mipi_dsi_driver *driver);
 
+#define mipi_dsi_driver_register(driver) \
+       mipi_dsi_driver_register_full(driver, THIS_MODULE)
+
 #define module_mipi_dsi_driver(__mipi_dsi_driver) \
        module_driver(__mipi_dsi_driver, mipi_dsi_driver_register, \
                        mipi_dsi_driver_unregister)
index 28931a23d96cd9ea1947f9b881e50cdb5e29a86b..70595ff565baa45190faaae5c42630fe04a1beff 100644 (file)
@@ -127,11 +127,13 @@ void drm_modeset_unlock(struct drm_modeset_lock *lock);
 
 struct drm_device;
 struct drm_crtc;
+struct drm_plane;
 
 void drm_modeset_lock_all(struct drm_device *dev);
 int __drm_modeset_lock_all(struct drm_device *dev, bool trylock);
 void drm_modeset_unlock_all(struct drm_device *dev);
-void drm_modeset_lock_crtc(struct drm_crtc *crtc);
+void drm_modeset_lock_crtc(struct drm_crtc *crtc,
+                          struct drm_plane *plane);
 void drm_modeset_unlock_crtc(struct drm_crtc *crtc);
 void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
 struct drm_modeset_acquire_ctx *
index c48f14d886902989fe18f5860d4bf10832a0b782..a185392cafebdb792fa386ef632bf9b950142184 100644 (file)
@@ -49,6 +49,10 @@ extern int drm_crtc_init(struct drm_device *dev,
 
 /**
  * drm_plane_helper_funcs - helper operations for CRTCs
+ * @prepare_fb: prepare a framebuffer for use by the plane
+ * @cleanup_fb: cleanup a framebuffer when it's no longer used by the plane
+ * @atomic_check: check that a given atomic state is valid and can be applied
+ * @atomic_update: apply an atomic state to the plane
  *
  * The helper operations are called by the mid-layer CRTC helper.
  */
@@ -60,7 +64,8 @@ struct drm_plane_helper_funcs {
 
        int (*atomic_check)(struct drm_plane *plane,
                            struct drm_plane_state *state);
-       void (*atomic_update)(struct drm_plane *plane);
+       void (*atomic_update)(struct drm_plane *plane,
+                             struct drm_plane_state *old_state);
 };
 
 static inline void drm_plane_helper_add(struct drm_plane *plane,
index a929f86d0dddd52816d6fdfc41905b8fab76da88..d72b5b35f15edd965b89de2c4759bd9bc964f14f 100644 (file)
@@ -60,7 +60,7 @@
 #define ESC1_CLK_SRC                   43
 #define HDMI_CLK_SRC                   44
 #define VSYNC_CLK_SRC                  45
-#define RBCPR_CLK_SRC                  46
+#define MMSS_RBCPR_CLK_SRC             46
 #define RBBMTIMER_CLK_SRC              47
 #define MAPLE_CLK_SRC                  48
 #define VDP_CLK_SRC                    49
index be5fd38bd5a05d83eaac250055defcccacafe054..5d858e02997f5248d8a50150d870248e8146f4e6 100644 (file)
  * position @h. For example
  * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000.
  */
-#define GENMASK(h, l)          (((U32_C(1) << ((h) - (l) + 1)) - 1) << (l))
-#define GENMASK_ULL(h, l)      (((U64_C(1) << ((h) - (l) + 1)) - 1) << (l))
+#define GENMASK(h, l) \
+       (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
+
+#define GENMASK_ULL(h, l) \
+       (((~0ULL) << (l)) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h))))
 
 extern unsigned int __sw_hweight8(unsigned int w);
 extern unsigned int __sw_hweight16(unsigned int w);
index 6992afc6ba7f96fda9dba202f771fe7e28f807fe..b37ea95bc348f15b16a9c0d095588379b12edbee 100644 (file)
@@ -99,6 +99,12 @@ inval_skb:
        return 1;
 }
 
+static inline bool can_is_canfd_skb(const struct sk_buff *skb)
+{
+       /* the CAN specific type of skb is identified by its data length */
+       return skb->len == CANFD_MTU;
+}
+
 /* get data length from can_dlc with sanitized can_dlc */
 u8 can_dlc2len(u8 can_dlc);
 
index be21af149f119394c68bd8018a8de39f2db067ee..2839c639f0920942d1e835dd464598432e22e974 100644 (file)
@@ -352,7 +352,6 @@ struct clk_divider {
 #define CLK_DIVIDER_READ_ONLY          BIT(5)
 
 extern const struct clk_ops clk_divider_ops;
-extern const struct clk_ops clk_divider_ro_ops;
 struct clk *clk_register_divider(struct device *dev, const char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 shift, u8 width,
index 11c0182a153b8a9025a4b4eab4486fe99a07949f..cbb5790a35cd7f360ac602ddca36ab331319a649 100644 (file)
@@ -1,9 +1,24 @@
 /*
  * Copyright (C) 2012 Avionic Design GmbH
  *
- * 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.
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
  */
 
 #ifndef __LINUX_HDMI_H_
index 8bbd7bc1043d9c4d26ffff38b35b8540093fdb71..03fa332ad2a8cec4e26c212b9333e56f0c6d6169 100644 (file)
@@ -72,7 +72,7 @@ struct iio_event_data {
 
 #define IIO_EVENT_CODE_EXTRACT_TYPE(mask) ((mask >> 56) & 0xFF)
 
-#define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 48) & 0xCF)
+#define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 48) & 0x7F)
 
 #define IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(mask) ((mask >> 32) & 0xFF)
 
index 0068708161ffa6954f320d7de7d4ebb86dd2a889..0a21fbefdfbec1a693ed09c3d256b8059760655e 100644 (file)
@@ -242,7 +242,7 @@ static inline void in_dev_put(struct in_device *idev)
 static __inline__ __be32 inet_make_mask(int logmask)
 {
        if (logmask)
-               return htonl(~((1<<(32-logmask))-1));
+               return htonl(~((1U<<(32-logmask))-1));
        return 0;
 }
 
index 8422b4ed6882be8e8ece65f9a1bcd2ceb5af2bfb..b9376cd5a187e818c28c09935eb022a1920848a8 100644 (file)
@@ -77,11 +77,6 @@ static inline unsigned int kstat_cpu_irqs_sum(unsigned int cpu)
        return kstat_cpu(cpu).irqs_sum;
 }
 
-/*
- * Lock/unlock the current runqueue - to extract task statistics:
- */
-extern unsigned long long task_delta_exec(struct task_struct *);
-
 extern void account_user_time(struct task_struct *, cputime_t, cputime_t);
 extern void account_system_time(struct task_struct *, int, cputime_t, cputime_t);
 extern void account_steal_time(cputime_t);
index ea53b04993f22745028d402e0238a30c91595afb..a6059bdf7b03baa4955c069637f686b3d709d819 100644 (file)
@@ -703,7 +703,7 @@ void kvm_arch_sync_events(struct kvm *kvm);
 int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu);
 void kvm_vcpu_kick(struct kvm_vcpu *vcpu);
 
-bool kvm_is_mmio_pfn(pfn_t pfn);
+bool kvm_is_reserved_pfn(pfn_t pfn);
 
 struct kvm_irq_ack_notifier {
        struct hlist_node link;
index 88787bb4b3b93fe08d322c2a54a183486427a2af..94d19f64cecf000e55b21b9a8662d15b91658c11 100644 (file)
@@ -98,11 +98,11 @@ struct mmu_notifier_ops {
        /*
         * invalidate_range_start() and invalidate_range_end() must be
         * paired and are called only when the mmap_sem and/or the
-        * locks protecting the reverse maps are held. The subsystem
-        * must guarantee that no additional references are taken to
-        * the pages in the range established between the call to
-        * invalidate_range_start() and the matching call to
-        * invalidate_range_end().
+        * locks protecting the reverse maps are held. If the subsystem
+        * can't guarantee that no additional references are taken to
+        * the pages in the range, it has to implement the
+        * invalidate_range() notifier to remove any references taken
+        * after invalidate_range_start().
         *
         * Invalidation of multiple concurrent ranges may be
         * optionally permitted by the driver. Either way the
@@ -144,6 +144,29 @@ struct mmu_notifier_ops {
        void (*invalidate_range_end)(struct mmu_notifier *mn,
                                     struct mm_struct *mm,
                                     unsigned long start, unsigned long end);
+
+       /*
+        * invalidate_range() is either called between
+        * invalidate_range_start() and invalidate_range_end() when the
+        * VM has to free pages that where unmapped, but before the
+        * pages are actually freed, or outside of _start()/_end() when
+        * a (remote) TLB is necessary.
+        *
+        * If invalidate_range() is used to manage a non-CPU TLB with
+        * shared page-tables, it not necessary to implement the
+        * invalidate_range_start()/end() notifiers, as
+        * invalidate_range() alread catches the points in time when an
+        * external TLB range needs to be flushed.
+        *
+        * The invalidate_range() function is called under the ptl
+        * spin-lock and not allowed to sleep.
+        *
+        * Note that this function might be called with just a sub-range
+        * of what was passed to invalidate_range_start()/end(), if
+        * called between those functions.
+        */
+       void (*invalidate_range)(struct mmu_notifier *mn, struct mm_struct *mm,
+                                unsigned long start, unsigned long end);
 };
 
 /*
@@ -190,6 +213,8 @@ extern void __mmu_notifier_invalidate_range_start(struct mm_struct *mm,
                                  unsigned long start, unsigned long end);
 extern void __mmu_notifier_invalidate_range_end(struct mm_struct *mm,
                                  unsigned long start, unsigned long end);
+extern void __mmu_notifier_invalidate_range(struct mm_struct *mm,
+                                 unsigned long start, unsigned long end);
 
 static inline void mmu_notifier_release(struct mm_struct *mm)
 {
@@ -242,6 +267,13 @@ static inline void mmu_notifier_invalidate_range_end(struct mm_struct *mm,
                __mmu_notifier_invalidate_range_end(mm, start, end);
 }
 
+static inline void mmu_notifier_invalidate_range(struct mm_struct *mm,
+                                 unsigned long start, unsigned long end)
+{
+       if (mm_has_notifiers(mm))
+               __mmu_notifier_invalidate_range(mm, start, end);
+}
+
 static inline void mmu_notifier_mm_init(struct mm_struct *mm)
 {
        mm->mmu_notifier_mm = NULL;
@@ -279,6 +311,44 @@ static inline void mmu_notifier_mm_destroy(struct mm_struct *mm)
        __young;                                                        \
 })
 
+#define        ptep_clear_flush_notify(__vma, __address, __ptep)               \
+({                                                                     \
+       unsigned long ___addr = __address & PAGE_MASK;                  \
+       struct mm_struct *___mm = (__vma)->vm_mm;                       \
+       pte_t ___pte;                                                   \
+                                                                       \
+       ___pte = ptep_clear_flush(__vma, __address, __ptep);            \
+       mmu_notifier_invalidate_range(___mm, ___addr,                   \
+                                       ___addr + PAGE_SIZE);           \
+                                                                       \
+       ___pte;                                                         \
+})
+
+#define pmdp_clear_flush_notify(__vma, __haddr, __pmd)                 \
+({                                                                     \
+       unsigned long ___haddr = __haddr & HPAGE_PMD_MASK;              \
+       struct mm_struct *___mm = (__vma)->vm_mm;                       \
+       pmd_t ___pmd;                                                   \
+                                                                       \
+       ___pmd = pmdp_clear_flush(__vma, __haddr, __pmd);               \
+       mmu_notifier_invalidate_range(___mm, ___haddr,                  \
+                                     ___haddr + HPAGE_PMD_SIZE);       \
+                                                                       \
+       ___pmd;                                                         \
+})
+
+#define pmdp_get_and_clear_notify(__mm, __haddr, __pmd)                        \
+({                                                                     \
+       unsigned long ___haddr = __haddr & HPAGE_PMD_MASK;              \
+       pmd_t ___pmd;                                                   \
+                                                                       \
+       ___pmd = pmdp_get_and_clear(__mm, __haddr, __pmd);              \
+       mmu_notifier_invalidate_range(__mm, ___haddr,                   \
+                                     ___haddr + HPAGE_PMD_SIZE);       \
+                                                                       \
+       ___pmd;                                                         \
+})
+
 /*
  * set_pte_at_notify() sets the pte _after_ running the notifier.
  * This is safe to start by updating the secondary MMUs, because the primary MMU
@@ -342,6 +412,11 @@ static inline void mmu_notifier_invalidate_range_end(struct mm_struct *mm,
 {
 }
 
+static inline void mmu_notifier_invalidate_range(struct mm_struct *mm,
+                                 unsigned long start, unsigned long end)
+{
+}
+
 static inline void mmu_notifier_mm_init(struct mm_struct *mm)
 {
 }
@@ -352,6 +427,9 @@ static inline void mmu_notifier_mm_destroy(struct mm_struct *mm)
 
 #define ptep_clear_flush_young_notify ptep_clear_flush_young
 #define pmdp_clear_flush_young_notify pmdp_clear_flush_young
+#define        ptep_clear_flush_notify ptep_clear_flush
+#define pmdp_clear_flush_notify pmdp_clear_flush
+#define pmdp_get_and_clear_notify pmdp_get_and_clear
 #define set_pte_at_notify set_pte_at
 
 #endif /* CONFIG_MMU_NOTIFIER */
index 5be8db45e368b23eb4c0d7b16b92f9db49290998..4c8ac5fcc224e2ab4c6af62cd01e130b2bf7dbb1 100644 (file)
@@ -331,6 +331,7 @@ struct pci_dev {
        unsigned int    is_added:1;
        unsigned int    is_busmaster:1; /* device is busmaster */
        unsigned int    no_msi:1;       /* device may not use msi */
+       unsigned int    no_64bit_msi:1; /* device may only use 32-bit MSIs */
        unsigned int    block_cfg_access:1;     /* config space access is blocked */
        unsigned int    broken_parity_status:1; /* Device generates false positive parity */
        unsigned int    irq_reroute_variant:2;  /* device needs IRQ rerouting variant */
index d5c89e0dd0e6725c614b491c78b5bfafe9cc46f4..51ce60c35f4c69a6df45d1e104d56d5e47798a78 100644 (file)
@@ -133,7 +133,13 @@ static inline bool __ref_is_percpu(struct percpu_ref *ref,
        /* paired with smp_store_release() in percpu_ref_reinit() */
        smp_read_barrier_depends();
 
-       if (unlikely(percpu_ptr & __PERCPU_REF_ATOMIC))
+       /*
+        * Theoretically, the following could test just ATOMIC; however,
+        * then we'd have to mask off DEAD separately as DEAD may be
+        * visible without ATOMIC if we race with percpu_ref_kill().  DEAD
+        * implies ATOMIC anyway.  Test them together.
+        */
+       if (unlikely(percpu_ptr & __PERCPU_REF_ATOMIC_DEAD))
                return false;
 
        *percpu_countp = (unsigned long __percpu *)percpu_ptr;
diff --git a/include/linux/platform_data/rcar-du.h b/include/linux/platform_data/rcar-du.h
deleted file mode 100644 (file)
index a5f045e..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * rcar_du.h  --  R-Car Display Unit DRM driver
- *
- * Copyright (C) 2013 Renesas Corporation
- *
- * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.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.
- */
-
-#ifndef __RCAR_DU_H__
-#define __RCAR_DU_H__
-
-#include <video/videomode.h>
-
-enum rcar_du_output {
-       RCAR_DU_OUTPUT_DPAD0,
-       RCAR_DU_OUTPUT_DPAD1,
-       RCAR_DU_OUTPUT_LVDS0,
-       RCAR_DU_OUTPUT_LVDS1,
-       RCAR_DU_OUTPUT_TCON,
-       RCAR_DU_OUTPUT_MAX,
-};
-
-enum rcar_du_encoder_type {
-       RCAR_DU_ENCODER_UNUSED = 0,
-       RCAR_DU_ENCODER_NONE,
-       RCAR_DU_ENCODER_VGA,
-       RCAR_DU_ENCODER_LVDS,
-};
-
-struct rcar_du_panel_data {
-       unsigned int width_mm;          /* Panel width in mm */
-       unsigned int height_mm;         /* Panel height in mm */
-       struct videomode mode;
-};
-
-struct rcar_du_connector_lvds_data {
-       struct rcar_du_panel_data panel;
-};
-
-struct rcar_du_connector_vga_data {
-       /* TODO: Add DDC information for EDID retrieval */
-};
-
-/*
- * struct rcar_du_encoder_data - Encoder platform data
- * @type: the encoder type (RCAR_DU_ENCODER_*)
- * @output: the DU output the connector is connected to (RCAR_DU_OUTPUT_*)
- * @connector.lvds: platform data for LVDS connectors
- * @connector.vga: platform data for VGA connectors
- *
- * Encoder platform data describes an on-board encoder, its associated DU SoC
- * output, and the connector.
- */
-struct rcar_du_encoder_data {
-       enum rcar_du_encoder_type type;
-       enum rcar_du_output output;
-
-       union {
-               struct rcar_du_connector_lvds_data lvds;
-               struct rcar_du_connector_vga_data vga;
-       } connector;
-};
-
-struct rcar_du_platform_data {
-       struct rcar_du_encoder_data *encoders;
-       unsigned int num_encoders;
-};
-
-#endif /* __RCAR_DU_H__ */
index fe7994c48b75685174134e7817bbb20ef375f890..b2828a06a5a63355f1aa2be27e74a472cc99fc62 100644 (file)
@@ -37,6 +37,8 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
 int inet_ctl_sock_create(struct sock **sk, unsigned short family,
                         unsigned short type, unsigned char protocol,
                         struct net *net);
+int inet_recv_error(struct sock *sk, struct msghdr *msg, int len,
+                   int *addr_len);
 
 static inline void inet_ctl_sock_destroy(struct sock *sk)
 {
index 845c596bf594c5ac297320c1a3dfe8f34cf702b4..3ae969e3acf016474413e1209381c60091befe1a 100644 (file)
@@ -396,14 +396,12 @@ struct nft_rule {
 /**
  *     struct nft_trans - nf_tables object update in transaction
  *
- *     @rcu_head: rcu head to defer release of transaction data
  *     @list: used internally
  *     @msg_type: message type
  *     @ctx: transaction context
  *     @data: internal information related to the transaction
  */
 struct nft_trans {
-       struct rcu_head                 rcu_head;
        struct list_head                list;
        int                             msg_type;
        struct nft_ctx                  ctx;
index d5f59f3fc35df67141c8234a8741ab5b49501ad1..57cccd0052e58dd124ec997174d8cd9ff885be99 100644 (file)
@@ -8,6 +8,12 @@
 #define VNI_HASH_BITS  10
 #define VNI_HASH_SIZE  (1<<VNI_HASH_BITS)
 
+/* VXLAN protocol header */
+struct vxlanhdr {
+       __be32 vx_flags;
+       __be32 vx_vni;
+};
+
 struct vxlan_sock;
 typedef void (vxlan_rcv_t)(struct vxlan_sock *vh, struct sk_buff *skb, __be32 key);
 
@@ -45,6 +51,18 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
                   __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df,
                   __be16 src_port, __be16 dst_port, __be32 vni, bool xnet);
 
+static inline bool vxlan_gso_check(struct sk_buff *skb)
+{
+       if ((skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL) &&
+           (skb->inner_protocol_type != ENCAP_TYPE_ETHER ||
+            skb->inner_protocol != htons(ETH_P_TEB) ||
+            (skb_inner_mac_header(skb) - skb_transport_header(skb) !=
+             sizeof(struct udphdr) + sizeof(struct vxlanhdr))))
+               return false;
+
+       return true;
+}
+
 /* IP header + UDP + VXLAN + Ethernet header */
 #define VXLAN_HEADROOM (20 + 8 + 8 + 14)
 /* IPv6 header + UDP + VXLAN + Ethernet header */
index e862497f75568d11cd4deb4f5f5a06712f63d6de..8bb00a27e219e902c9bdc2ac52f0a7c3ed53f005 100644 (file)
@@ -184,6 +184,8 @@ struct snd_pcm_ops {
 #define SNDRV_PCM_FMTBIT_DSD_U8                _SNDRV_PCM_FMTBIT(DSD_U8)
 #define SNDRV_PCM_FMTBIT_DSD_U16_LE    _SNDRV_PCM_FMTBIT(DSD_U16_LE)
 #define SNDRV_PCM_FMTBIT_DSD_U32_LE    _SNDRV_PCM_FMTBIT(DSD_U32_LE)
+#define SNDRV_PCM_FMTBIT_DSD_U16_BE    _SNDRV_PCM_FMTBIT(DSD_U16_BE)
+#define SNDRV_PCM_FMTBIT_DSD_U32_BE    _SNDRV_PCM_FMTBIT(DSD_U32_BE)
 
 #ifdef SNDRV_LITTLE_ENDIAN
 #define SNDRV_PCM_FMTBIT_S16           SNDRV_PCM_FMTBIT_S16_LE
index 2883a7a6f9f3a932b38843d20a8887986804fc00..98f2ade0266eb9a28ae6340b2908bd8fabea0eca 100644 (file)
@@ -102,6 +102,8 @@ struct snd_soc_dpcm_runtime {
        /* state and update */
        enum snd_soc_dpcm_update runtime_update;
        enum snd_soc_dpcm_state state;
+
+       int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */
 };
 
 /* can this BE stop and free */
index 94db6a2c3540c1cb5b561c63933ca8c8339be80e..63116362543c7c3d58a207cbd4e19fb1828b9eeb 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/ktime.h>
 #include <linux/tracepoint.h>
 
+struct host1x_bo;
+
 DECLARE_EVENT_CLASS(host1x,
        TP_PROTO(const char *name),
        TP_ARGS(name),
@@ -79,14 +81,14 @@ TRACE_EVENT(host1x_cdma_push,
 );
 
 TRACE_EVENT(host1x_cdma_push_gather,
-       TP_PROTO(const char *name, u32 mem_id,
+       TP_PROTO(const char *name, struct host1x_bo *bo,
                        u32 words, u32 offset, void *cmdbuf),
 
-       TP_ARGS(name, mem_id, words, offset, cmdbuf),
+       TP_ARGS(name, bo, words, offset, cmdbuf),
 
        TP_STRUCT__entry(
                __field(const char *, name)
-               __field(u32, mem_id)
+               __field(struct host1x_bo *, bo)
                __field(u32, words)
                __field(u32, offset)
                __field(bool, cmdbuf)
@@ -100,13 +102,13 @@ TRACE_EVENT(host1x_cdma_push_gather,
                }
                __entry->cmdbuf = cmdbuf;
                __entry->name = name;
-               __entry->mem_id = mem_id;
+               __entry->bo = bo;
                __entry->words = words;
                __entry->offset = offset;
        ),
 
-       TP_printk("name=%s, mem_id=%08x, words=%u, offset=%d, contents=[%s]",
-         __entry->name, __entry->mem_id,
+       TP_printk("name=%s, bo=%p, words=%u, offset=%d, contents=[%s]",
+         __entry->name, __entry->bo,
          __entry->words, __entry->offset,
          __print_hex(__get_dynamic_array(cmdbuf),
                  __entry->cmdbuf ? __entry->words * 4 : 0))
@@ -221,12 +223,13 @@ TRACE_EVENT(host1x_syncpt_load_min,
 );
 
 TRACE_EVENT(host1x_syncpt_wait_check,
-       TP_PROTO(void *mem_id, u32 offset, u32 syncpt_id, u32 thresh, u32 min),
+       TP_PROTO(struct host1x_bo *bo, u32 offset, u32 syncpt_id, u32 thresh,
+                u32 min),
 
-       TP_ARGS(mem_id, offset, syncpt_id, thresh, min),
+       TP_ARGS(bo, offset, syncpt_id, thresh, min),
 
        TP_STRUCT__entry(
-               __field(void *, mem_id)
+               __field(struct host1x_bo *, bo)
                __field(u32, offset)
                __field(u32, syncpt_id)
                __field(u32, thresh)
@@ -234,15 +237,15 @@ TRACE_EVENT(host1x_syncpt_wait_check,
        ),
 
        TP_fast_assign(
-               __entry->mem_id = mem_id;
+               __entry->bo = bo;
                __entry->offset = offset;
                __entry->syncpt_id = syncpt_id;
                __entry->thresh = thresh;
                __entry->min = min;
        ),
 
-       TP_printk("mem_id=%p, offset=%05x, id=%d, thresh=%d, current=%d",
-               __entry->mem_id, __entry->offset,
+       TP_printk("bo=%p, offset=%05x, id=%d, thresh=%d, current=%d",
+               __entry->bo, __entry->offset,
                __entry->syncpt_id, __entry->thresh,
                __entry->min)
 );
index a0db2d4aa5f0125349adc7ec6516fbfbda63be43..86574b0005ff0a476fa2299b8ef73de418670024 100644 (file)
@@ -286,6 +286,8 @@ struct drm_mode_get_property {
        char name[DRM_PROP_NAME_LEN];
 
        __u32 count_values;
+       /* This is only used to count enum values, not blobs. The _blobs is
+        * simply because of a historical reason, i.e. backwards compat. */
        __u32 count_enum_blobs;
 };
 
diff --git a/include/uapi/linux/kfd_ioctl.h b/include/uapi/linux/kfd_ioctl.h
new file mode 100644 (file)
index 0000000..7acef41
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef KFD_IOCTL_H_INCLUDED
+#define KFD_IOCTL_H_INCLUDED
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define KFD_IOCTL_MAJOR_VERSION 1
+#define KFD_IOCTL_MINOR_VERSION 0
+
+struct kfd_ioctl_get_version_args {
+       uint32_t major_version; /* from KFD */
+       uint32_t minor_version; /* from KFD */
+};
+
+/* For kfd_ioctl_create_queue_args.queue_type. */
+#define KFD_IOC_QUEUE_TYPE_COMPUTE     0
+#define KFD_IOC_QUEUE_TYPE_SDMA                1
+#define KFD_IOC_QUEUE_TYPE_COMPUTE_AQL 2
+
+#define KFD_MAX_QUEUE_PERCENTAGE       100
+#define KFD_MAX_QUEUE_PRIORITY         15
+
+struct kfd_ioctl_create_queue_args {
+       uint64_t ring_base_address;     /* to KFD */
+       uint64_t write_pointer_address; /* from KFD */
+       uint64_t read_pointer_address;  /* from KFD */
+       uint64_t doorbell_offset;       /* from KFD */
+
+       uint32_t ring_size;             /* to KFD */
+       uint32_t gpu_id;                /* to KFD */
+       uint32_t queue_type;            /* to KFD */
+       uint32_t queue_percentage;      /* to KFD */
+       uint32_t queue_priority;        /* to KFD */
+       uint32_t queue_id;              /* from KFD */
+
+       uint64_t eop_buffer_address;    /* to KFD */
+       uint64_t eop_buffer_size;       /* to KFD */
+       uint64_t ctx_save_restore_address; /* to KFD */
+       uint64_t ctx_save_restore_size; /* to KFD */
+};
+
+struct kfd_ioctl_destroy_queue_args {
+       uint32_t queue_id;              /* to KFD */
+       uint32_t pad;
+};
+
+struct kfd_ioctl_update_queue_args {
+       uint64_t ring_base_address;     /* to KFD */
+
+       uint32_t queue_id;              /* to KFD */
+       uint32_t ring_size;             /* to KFD */
+       uint32_t queue_percentage;      /* to KFD */
+       uint32_t queue_priority;        /* to KFD */
+};
+
+/* For kfd_ioctl_set_memory_policy_args.default_policy and alternate_policy */
+#define KFD_IOC_CACHE_POLICY_COHERENT 0
+#define KFD_IOC_CACHE_POLICY_NONCOHERENT 1
+
+struct kfd_ioctl_set_memory_policy_args {
+       uint64_t alternate_aperture_base;       /* to KFD */
+       uint64_t alternate_aperture_size;       /* to KFD */
+
+       uint32_t gpu_id;                        /* to KFD */
+       uint32_t default_policy;                /* to KFD */
+       uint32_t alternate_policy;              /* to KFD */
+       uint32_t pad;
+};
+
+/*
+ * All counters are monotonic. They are used for profiling of compute jobs.
+ * The profiling is done by userspace.
+ *
+ * In case of GPU reset, the counter should not be affected.
+ */
+
+struct kfd_ioctl_get_clock_counters_args {
+       uint64_t gpu_clock_counter;     /* from KFD */
+       uint64_t cpu_clock_counter;     /* from KFD */
+       uint64_t system_clock_counter;  /* from KFD */
+       uint64_t system_clock_freq;     /* from KFD */
+
+       uint32_t gpu_id;                /* to KFD */
+       uint32_t pad;
+};
+
+#define NUM_OF_SUPPORTED_GPUS 7
+
+struct kfd_process_device_apertures {
+       uint64_t lds_base;              /* from KFD */
+       uint64_t lds_limit;             /* from KFD */
+       uint64_t scratch_base;          /* from KFD */
+       uint64_t scratch_limit;         /* from KFD */
+       uint64_t gpuvm_base;            /* from KFD */
+       uint64_t gpuvm_limit;           /* from KFD */
+       uint32_t gpu_id;                /* from KFD */
+       uint32_t pad;
+};
+
+struct kfd_ioctl_get_process_apertures_args {
+       struct kfd_process_device_apertures
+                       process_apertures[NUM_OF_SUPPORTED_GPUS];/* from KFD */
+
+       /* from KFD, should be in the range [1 - NUM_OF_SUPPORTED_GPUS] */
+       uint32_t num_of_nodes;
+       uint32_t pad;
+};
+
+#define KFD_IOC_MAGIC 'K'
+
+#define KFD_IOC_GET_VERSION \
+               _IOR(KFD_IOC_MAGIC, 1, struct kfd_ioctl_get_version_args)
+
+#define KFD_IOC_CREATE_QUEUE \
+               _IOWR(KFD_IOC_MAGIC, 2, struct kfd_ioctl_create_queue_args)
+
+#define KFD_IOC_DESTROY_QUEUE \
+       _IOWR(KFD_IOC_MAGIC, 3, struct kfd_ioctl_destroy_queue_args)
+
+#define KFD_IOC_SET_MEMORY_POLICY \
+       _IOW(KFD_IOC_MAGIC, 4, struct kfd_ioctl_set_memory_policy_args)
+
+#define KFD_IOC_GET_CLOCK_COUNTERS \
+       _IOWR(KFD_IOC_MAGIC, 5, struct kfd_ioctl_get_clock_counters_args)
+
+#define KFD_IOC_GET_PROCESS_APERTURES \
+       _IOR(KFD_IOC_MAGIC, 6, struct kfd_ioctl_get_process_apertures_args)
+
+#define KFD_IOC_UPDATE_QUEUE \
+       _IOW(KFD_IOC_MAGIC, 7, struct kfd_ioctl_update_queue_args)
+
+#endif
index 6ee586728df97a0fc335a3c314e0828ac970023f..941d32f007dc250afb73a8045044d68b2646eecb 100644 (file)
@@ -220,7 +220,9 @@ typedef int __bitwise snd_pcm_format_t;
 #define        SNDRV_PCM_FORMAT_DSD_U8         ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */
 #define        SNDRV_PCM_FORMAT_DSD_U16_LE     ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */
 #define        SNDRV_PCM_FORMAT_DSD_U32_LE     ((__force snd_pcm_format_t) 50) /* DSD, 4-byte samples DSD (x32), little endian */
-#define        SNDRV_PCM_FORMAT_LAST           SNDRV_PCM_FORMAT_DSD_U32_LE
+#define        SNDRV_PCM_FORMAT_DSD_U16_BE     ((__force snd_pcm_format_t) 51) /* DSD, 2-byte samples DSD (x16), big endian */
+#define        SNDRV_PCM_FORMAT_DSD_U32_BE     ((__force snd_pcm_format_t) 52) /* DSD, 4-byte samples DSD (x32), big endian */
+#define        SNDRV_PCM_FORMAT_LAST           SNDRV_PCM_FORMAT_DSD_U32_BE
 
 #ifdef SNDRV_LITTLE_ENDIAN
 #define        SNDRV_PCM_FORMAT_S16            SNDRV_PCM_FORMAT_S16_LE
index 2b02c9fda790d667c29c304bca011901a4e30189..1cd5eef1fcddf3f53149522b0a482b7989e5a7a8 100644 (file)
@@ -1562,8 +1562,10 @@ static void perf_remove_from_context(struct perf_event *event, bool detach_group
 
        if (!task) {
                /*
-                * Per cpu events are removed via an smp call and
-                * the removal is always successful.
+                * Per cpu events are removed via an smp call. The removal can
+                * fail if the CPU is currently offline, but in that case we
+                * already called __perf_remove_from_context from
+                * perf_event_exit_cpu.
                 */
                cpu_function_call(event->cpu, __perf_remove_from_context, &re);
                return;
@@ -8117,7 +8119,7 @@ static void perf_pmu_rotate_stop(struct pmu *pmu)
 
 static void __perf_event_exit_context(void *__info)
 {
-       struct remove_event re = { .detach_group = false };
+       struct remove_event re = { .detach_group = true };
        struct perf_event_context *ctx = __info;
 
        perf_pmu_rotate_stop(ctx->pmu);
index 1d0af8a2c6469bda46438dbd8383cbf535d65077..d2a5689a6b2ec02248a5d4bafb0f5eac3043fd59 100644 (file)
@@ -193,7 +193,7 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr,
        }
 
        flush_cache_page(vma, addr, pte_pfn(*ptep));
-       ptep_clear_flush(vma, addr, ptep);
+       ptep_clear_flush_notify(vma, addr, ptep);
        set_pte_at_notify(mm, addr, ptep, mk_pte(kpage, vma->vm_page_prot));
 
        page_remove_rmap(page);
@@ -1640,7 +1640,6 @@ bool uprobe_deny_signal(void)
                if (__fatal_signal_pending(t) || arch_uprobe_xol_was_trapped(t)) {
                        utask->state = UTASK_SSTEP_TRAPPED;
                        set_tsk_thread_flag(t, TIF_UPROBE);
-                       set_tsk_thread_flag(t, TIF_NOTIFY_RESUME);
                }
        }
 
index 240157c13ddc88508a4aafa87d8350394b38e94b..24beb9bb4c3e228ac17e8b931f37c44091987d18 100644 (file)
@@ -2474,44 +2474,6 @@ DEFINE_PER_CPU(struct kernel_cpustat, kernel_cpustat);
 EXPORT_PER_CPU_SYMBOL(kstat);
 EXPORT_PER_CPU_SYMBOL(kernel_cpustat);
 
-/*
- * Return any ns on the sched_clock that have not yet been accounted in
- * @p in case that task is currently running.
- *
- * Called with task_rq_lock() held on @rq.
- */
-static u64 do_task_delta_exec(struct task_struct *p, struct rq *rq)
-{
-       u64 ns = 0;
-
-       /*
-        * Must be ->curr _and_ ->on_rq.  If dequeued, we would
-        * project cycles that may never be accounted to this
-        * thread, breaking clock_gettime().
-        */
-       if (task_current(rq, p) && task_on_rq_queued(p)) {
-               update_rq_clock(rq);
-               ns = rq_clock_task(rq) - p->se.exec_start;
-               if ((s64)ns < 0)
-                       ns = 0;
-       }
-
-       return ns;
-}
-
-unsigned long long task_delta_exec(struct task_struct *p)
-{
-       unsigned long flags;
-       struct rq *rq;
-       u64 ns = 0;
-
-       rq = task_rq_lock(p, &flags);
-       ns = do_task_delta_exec(p, rq);
-       task_rq_unlock(rq, p, &flags);
-
-       return ns;
-}
-
 /*
  * Return accounted runtime for the task.
  * In case the task is currently running, return the runtime plus current's
@@ -2521,7 +2483,7 @@ unsigned long long task_sched_runtime(struct task_struct *p)
 {
        unsigned long flags;
        struct rq *rq;
-       u64 ns = 0;
+       u64 ns;
 
 #if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
        /*
@@ -2540,7 +2502,16 @@ unsigned long long task_sched_runtime(struct task_struct *p)
 #endif
 
        rq = task_rq_lock(p, &flags);
-       ns = p->se.sum_exec_runtime + do_task_delta_exec(p, rq);
+       /*
+        * Must be ->curr _and_ ->on_rq.  If dequeued, we would
+        * project cycles that may never be accounted to this
+        * thread, breaking clock_gettime().
+        */
+       if (task_current(rq, p) && task_on_rq_queued(p)) {
+               update_rq_clock(rq);
+               p->sched_class->update_curr(rq);
+       }
+       ns = p->se.sum_exec_runtime;
        task_rq_unlock(rq, p, &flags);
 
        return ns;
@@ -6368,6 +6339,10 @@ static void sched_init_numa(void)
                if (!sched_debug())
                        break;
        }
+
+       if (!level)
+               return;
+
        /*
         * 'level' contains the number of unique distances, excluding the
         * identity distance node_distance(i,i).
@@ -7444,8 +7419,12 @@ void sched_move_task(struct task_struct *tsk)
        if (unlikely(running))
                put_prev_task(rq, tsk);
 
-       tg = container_of(task_css_check(tsk, cpu_cgrp_id,
-                               lockdep_is_held(&tsk->sighand->siglock)),
+       /*
+        * All callers are synchronized by task_rq_lock(); we do not use RCU
+        * which is pointless here. Thus, we pass "true" to task_css_check()
+        * to prevent lockdep warnings.
+        */
+       tg = container_of(task_css_check(tsk, cpu_cgrp_id, true),
                          struct task_group, css);
        tg = autogroup_task_group(tsk, tg);
        tsk->sched_task_group = tg;
index 5285332392d5b599788a90faa37615ccddc386d5..28fa9d9e92012a9245b2e95ce85bf301d320f8cc 100644 (file)
@@ -1701,4 +1701,6 @@ const struct sched_class dl_sched_class = {
        .prio_changed           = prio_changed_dl,
        .switched_from          = switched_from_dl,
        .switched_to            = switched_to_dl,
+
+       .update_curr            = update_curr_dl,
 };
index 34baa60f8a7bd11f03ccb1f754a08eb1029c46be..ef2b104b254cb8c60d954a92e62f0f8a626ed024 100644 (file)
@@ -726,6 +726,11 @@ static void update_curr(struct cfs_rq *cfs_rq)
        account_cfs_rq_runtime(cfs_rq, delta_exec);
 }
 
+static void update_curr_fair(struct rq *rq)
+{
+       update_curr(cfs_rq_of(&rq->curr->se));
+}
+
 static inline void
 update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
@@ -1179,6 +1184,13 @@ static void task_numa_compare(struct task_numa_env *env,
                cur = NULL;
        raw_spin_unlock_irq(&dst_rq->lock);
 
+       /*
+        * Because we have preemption enabled we can get migrated around and
+        * end try selecting ourselves (current == env->p) as a swap candidate.
+        */
+       if (cur == env->p)
+               goto unlock;
+
        /*
         * "imp" is the fault differential for the source task between the
         * source and destination node. Calculate the total differential for
@@ -7949,6 +7961,8 @@ const struct sched_class fair_sched_class = {
 
        .get_rr_interval        = get_rr_interval_fair,
 
+       .update_curr            = update_curr_fair,
+
 #ifdef CONFIG_FAIR_GROUP_SCHED
        .task_move_group        = task_move_group_fair,
 #endif
index 67ad4e7f506a2509a0493138662c0fec7dc4d7fa..c65dac8c97cdd5dd72f636455dcecc2742d9706d 100644 (file)
@@ -75,6 +75,10 @@ static unsigned int get_rr_interval_idle(struct rq *rq, struct task_struct *task
        return 0;
 }
 
+static void update_curr_idle(struct rq *rq)
+{
+}
+
 /*
  * Simple, special scheduling class for the per-CPU idle tasks:
  */
@@ -101,4 +105,5 @@ const struct sched_class idle_sched_class = {
 
        .prio_changed           = prio_changed_idle,
        .switched_to            = switched_to_idle,
+       .update_curr            = update_curr_idle,
 };
index d024e6ce30baf50037eac7c256dacc5bf27856f4..20bca398084ae770b36945e9aef238d954a6796e 100644 (file)
@@ -2128,6 +2128,8 @@ const struct sched_class rt_sched_class = {
 
        .prio_changed           = prio_changed_rt,
        .switched_to            = switched_to_rt,
+
+       .update_curr            = update_curr_rt,
 };
 
 #ifdef CONFIG_SCHED_DEBUG
index 24156c8434d1ebbe679a3fa6df45725aa7db3647..2df8ef067cc54ddd7a25c0b1cf45267214a2c31c 100644 (file)
@@ -1135,6 +1135,8 @@ struct sched_class {
        unsigned int (*get_rr_interval) (struct rq *rq,
                                         struct task_struct *task);
 
+       void (*update_curr) (struct rq *rq);
+
 #ifdef CONFIG_FAIR_GROUP_SCHED
        void (*task_move_group) (struct task_struct *p, int on_rq);
 #endif
index 67426e529f59c044eef35c88c8d906cab641bb64..79ffec45a6acd9415d31d90906b529a6bc0d752b 100644 (file)
@@ -102,6 +102,10 @@ get_rr_interval_stop(struct rq *rq, struct task_struct *task)
        return 0;
 }
 
+static void update_curr_stop(struct rq *rq)
+{
+}
+
 /*
  * Simple, special scheduling class for the per-CPU stop tasks:
  */
@@ -128,4 +132,5 @@ const struct sched_class stop_sched_class = {
 
        .prio_changed           = prio_changed_stop,
        .switched_to            = switched_to_stop,
+       .update_curr            = update_curr_stop,
 };
index 492b986195d53350abe899b0ecd059f91edb77a4..a16b67859e2a79929331c5008f96fd7f29ebbfc1 100644 (file)
@@ -553,7 +553,7 @@ static int cpu_timer_sample_group(const clockid_t which_clock,
                *sample = cputime_to_expires(cputime.utime);
                break;
        case CPUCLOCK_SCHED:
-               *sample = cputime.sum_exec_runtime + task_delta_exec(p);
+               *sample = cputime.sum_exec_runtime;
                break;
        }
        return 0;
index 7512dc978f1872fe4a395868ed0f3cbd30de2ad0..0211d2bd5e17551856da7ca97aea0849528b2ead 100644 (file)
@@ -10,7 +10,7 @@ endif
 lib-y := ctype.o string.o vsprintf.o cmdline.o \
         rbtree.o radix-tree.o dump_stack.o timerqueue.o\
         idr.o int_sqrt.o extable.o \
-        sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \
+        sha1.o md5.o irq_regs.o argv_split.o \
         proportions.o flex_proportions.o ratelimit.o show_mem.o \
         is_single_threaded.o plist.o decompress.o kobject_uevent.o \
         earlycpio.o
@@ -26,7 +26,7 @@ obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
         bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
         gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o clz_ctz.o \
         bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \
-        percpu-refcount.o percpu_ida.o hash.o rhashtable.o
+        percpu-refcount.o percpu_ida.o hash.o rhashtable.o reciprocal_div.o
 obj-y += string_helpers.o
 obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o
 obj-y += kstrtox.o
index 72b8fa36143328f728a44de1b5cd53b629653a0a..9129013732d72b323251ab680b0db39f2961aba9 100644 (file)
@@ -37,7 +37,7 @@ static void zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
 
        if (pte_present(pte)) {
                flush_cache_page(vma, addr, pte_pfn(pte));
-               pte = ptep_clear_flush(vma, addr, ptep);
+               pte = ptep_clear_flush_notify(vma, addr, ptep);
                page = vm_normal_page(vma, addr, pte);
                if (page) {
                        if (pte_dirty(pte))
index de984159cf0b8a0be6a73b9f421e9a0b4f75c599..1d89526ed53196576cfbf2f00f220eebe3f1511a 100644 (file)
@@ -1036,7 +1036,7 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
                goto out_free_pages;
        VM_BUG_ON_PAGE(!PageHead(page), page);
 
-       pmdp_clear_flush(vma, haddr, pmd);
+       pmdp_clear_flush_notify(vma, haddr, pmd);
        /* leave pmd empty until pte is filled */
 
        pgtable = pgtable_trans_huge_withdraw(mm, pmd);
@@ -1179,7 +1179,7 @@ alloc:
                pmd_t entry;
                entry = mk_huge_pmd(new_page, vma->vm_page_prot);
                entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
-               pmdp_clear_flush(vma, haddr, pmd);
+               pmdp_clear_flush_notify(vma, haddr, pmd);
                page_add_new_anon_rmap(new_page, vma, haddr);
                mem_cgroup_commit_charge(new_page, memcg, false);
                lru_cache_add_active_or_unevictable(new_page, vma);
@@ -1512,7 +1512,7 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
                pmd_t entry;
                ret = 1;
                if (!prot_numa) {
-                       entry = pmdp_get_and_clear(mm, addr, pmd);
+                       entry = pmdp_get_and_clear_notify(mm, addr, pmd);
                        if (pmd_numa(entry))
                                entry = pmd_mknonnuma(entry);
                        entry = pmd_modify(entry, newprot);
@@ -1644,6 +1644,7 @@ static int __split_huge_page_splitting(struct page *page,
                 * serialize against split_huge_page*.
                 */
                pmdp_splitting_flush(vma, address, pmd);
+
                ret = 1;
                spin_unlock(ptl);
        }
@@ -2834,7 +2835,7 @@ static void __split_huge_zero_page_pmd(struct vm_area_struct *vma,
        pmd_t _pmd;
        int i;
 
-       pmdp_clear_flush(vma, haddr, pmd);
+       pmdp_clear_flush_notify(vma, haddr, pmd);
        /* leave pmd empty until pte is filled */
 
        pgtable = pgtable_trans_huge_withdraw(mm, pmd);
index 9fd722769927f9e5bb5e03fb6516db7a5f7c8f42..2e6add04fa1b37bd451f8bbd89e6cec6ab26f614 100644 (file)
@@ -2598,8 +2598,11 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
                        }
                        set_huge_pte_at(dst, addr, dst_pte, entry);
                } else {
-                       if (cow)
+                       if (cow) {
                                huge_ptep_set_wrprotect(src, addr, src_pte);
+                               mmu_notifier_invalidate_range(src, mmun_start,
+                                                                  mmun_end);
+                       }
                        entry = huge_ptep_get(src_pte);
                        ptepage = pte_page(entry);
                        get_page(ptepage);
@@ -2899,6 +2902,7 @@ retry_avoidcopy:
 
                /* Break COW */
                huge_ptep_clear_flush(vma, address, ptep);
+               mmu_notifier_invalidate_range(mm, mmun_start, mmun_end);
                set_huge_pte_at(mm, address, ptep,
                                make_huge_pte(vma, new_page, 1));
                page_remove_rmap(old_page);
@@ -3374,6 +3378,7 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
         * and that page table be reused and filled with junk.
         */
        flush_tlb_range(vma, start, end);
+       mmu_notifier_invalidate_range(mm, start, end);
        mutex_unlock(&vma->vm_file->f_mapping->i_mmap_mutex);
        mmu_notifier_invalidate_range_end(mm, start, end);
 
index 6b2e337bc03c7d6c5fce5e33023bdb5d2f111789..d247efab5073abfaeb9c11e33fb87a2fbb8ebdb0 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -892,7 +892,7 @@ static int write_protect_page(struct vm_area_struct *vma, struct page *page,
                 * this assure us that no O_DIRECT can happen after the check
                 * or in the middle of the check.
                 */
-               entry = ptep_clear_flush(vma, addr, ptep);
+               entry = ptep_clear_flush_notify(vma, addr, ptep);
                /*
                 * Check that no O_DIRECT or similar I/O is in progress on the
                 * page
@@ -960,7 +960,7 @@ static int replace_page(struct vm_area_struct *vma, struct page *page,
        page_add_anon_rmap(kpage, vma, addr);
 
        flush_cache_page(vma, addr, pte_pfn(*ptep));
-       ptep_clear_flush(vma, addr, ptep);
+       ptep_clear_flush_notify(vma, addr, ptep);
        set_pte_at_notify(mm, addr, ptep, mk_pte(kpage, vma->vm_page_prot));
 
        page_remove_rmap(page);
index 3e503831e042a6aa7b96d2608ecb570dfffa0aa7..655fd3d34bb0908e6e18d7b084342f6132f85521 100644 (file)
@@ -238,6 +238,7 @@ static void tlb_flush_mmu_tlbonly(struct mmu_gather *tlb)
 {
        tlb->need_flush = 0;
        tlb_flush(tlb);
+       mmu_notifier_invalidate_range(tlb->mm, tlb->start, tlb->end);
 #ifdef CONFIG_HAVE_RCU_TABLE_FREE
        tlb_table_flush(tlb);
 #endif
@@ -2234,7 +2235,7 @@ gotten:
                 * seen in the presence of one thread doing SMC and another
                 * thread doing COW.
                 */
-               ptep_clear_flush(vma, address, page_table);
+               ptep_clear_flush_notify(vma, address, page_table);
                page_add_new_anon_rmap(new_page, vma, address);
                mem_cgroup_commit_charge(new_page, memcg, false);
                lru_cache_add_active_or_unevictable(new_page, vma);
index 01439953abf548690ac17f1b994511b587e9326a..41945cb0ca38d318d88a4361ae01ddf2dea4a7b1 100644 (file)
@@ -1854,7 +1854,7 @@ fail_putback:
         */
        flush_cache_range(vma, mmun_start, mmun_end);
        page_add_anon_rmap(new_page, vma, mmun_start);
-       pmdp_clear_flush(vma, mmun_start, pmd);
+       pmdp_clear_flush_notify(vma, mmun_start, pmd);
        set_pmd_at(mm, mmun_start, pmd, entry);
        flush_tlb_range(vma, mmun_start, mmun_end);
        update_mmu_cache_pmd(vma, address, &entry);
@@ -1862,6 +1862,7 @@ fail_putback:
        if (page_count(page) != 2) {
                set_pmd_at(mm, mmun_start, pmd, orig_entry);
                flush_tlb_range(vma, mmun_start, mmun_end);
+               mmu_notifier_invalidate_range(mm, mmun_start, mmun_end);
                update_mmu_cache_pmd(vma, address, &entry);
                page_remove_rmap(new_page);
                goto fail_putback;
index 2c8da9825fe3482740ba4f4f2a0a003fabafd519..3b9b3d0741b2a1546837761d90f7eec2c0b3b18b 100644 (file)
@@ -193,6 +193,16 @@ void __mmu_notifier_invalidate_range_end(struct mm_struct *mm,
 
        id = srcu_read_lock(&srcu);
        hlist_for_each_entry_rcu(mn, &mm->mmu_notifier_mm->list, hlist) {
+               /*
+                * Call invalidate_range here too to avoid the need for the
+                * subsystem of having to register an invalidate_range_end
+                * call-back when there is invalidate_range already. Usually a
+                * subsystem registers either invalidate_range_start()/end() or
+                * invalidate_range(), so this will be no additional overhead
+                * (besides the pointer check).
+                */
+               if (mn->ops->invalidate_range)
+                       mn->ops->invalidate_range(mn, mm, start, end);
                if (mn->ops->invalidate_range_end)
                        mn->ops->invalidate_range_end(mn, mm, start, end);
        }
@@ -200,6 +210,21 @@ void __mmu_notifier_invalidate_range_end(struct mm_struct *mm,
 }
 EXPORT_SYMBOL_GPL(__mmu_notifier_invalidate_range_end);
 
+void __mmu_notifier_invalidate_range(struct mm_struct *mm,
+                                 unsigned long start, unsigned long end)
+{
+       struct mmu_notifier *mn;
+       int id;
+
+       id = srcu_read_lock(&srcu);
+       hlist_for_each_entry_rcu(mn, &mm->mmu_notifier_mm->list, hlist) {
+               if (mn->ops->invalidate_range)
+                       mn->ops->invalidate_range(mn, mm, start, end);
+       }
+       srcu_read_unlock(&srcu, id);
+}
+EXPORT_SYMBOL_GPL(__mmu_notifier_invalidate_range);
+
 static int do_mmu_notifier_register(struct mmu_notifier *mn,
                                    struct mm_struct *mm,
                                    int take_mmap_sem)
index 19886fb2f13aac6a659ba1ae8b9e4db2f8efa7a4..d3eb1e02d1c681fd21e1f1752b0327349b24accd 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1378,7 +1378,7 @@ static int try_to_unmap_cluster(unsigned long cursor, unsigned int *mapcount,
 
                /* Nuke the page table entry. */
                flush_cache_page(vma, address, pte_pfn(*pte));
-               pteval = ptep_clear_flush(vma, address, pte);
+               pteval = ptep_clear_flush_notify(vma, address, pte);
 
                /* If nonlinear, store the file page offset in the pte. */
                if (page->index != linear_page_index(vma, address)) {
index 648d79ccf46244a5769c1703361cf35db4cfeb09..c465876c7861814ba545cf83783c7ba11bbd91eb 100644 (file)
@@ -813,10 +813,9 @@ static void __br_multicast_send_query(struct net_bridge *br,
                return;
 
        if (port) {
-               __skb_push(skb, sizeof(struct ethhdr));
                skb->dev = port->dev;
                NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
-                       dev_queue_xmit);
+                       br_dev_queue_push_xmit);
        } else {
                br_multicast_select_own_querier(br, ip, skb);
                netif_rx(skb);
index 2ff9706647f2cb9f7930d22d0a3092fb3fe0d225..e5ec470b851f1f55fe37ec4ecaf557d75483af26 100644 (file)
@@ -280,6 +280,7 @@ static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = {
        [IFLA_BRPORT_MODE]      = { .type = NLA_U8 },
        [IFLA_BRPORT_GUARD]     = { .type = NLA_U8 },
        [IFLA_BRPORT_PROTECT]   = { .type = NLA_U8 },
+       [IFLA_BRPORT_FAST_LEAVE]= { .type = NLA_U8 },
        [IFLA_BRPORT_LEARNING]  = { .type = NLA_U8 },
        [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
 };
index a6882686ca3a10fc3be7ced6299dc7385ffd239d..b9b7dfaf202b9be668bf29153593aa2c7dba86ee 100644 (file)
@@ -2685,13 +2685,20 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
        int idx = 0;
        u32 portid = NETLINK_CB(cb->skb).portid;
        u32 seq = cb->nlh->nlmsg_seq;
-       struct nlattr *extfilt;
        u32 filter_mask = 0;
 
-       extfilt = nlmsg_find_attr(cb->nlh, sizeof(struct ifinfomsg),
-                                 IFLA_EXT_MASK);
-       if (extfilt)
-               filter_mask = nla_get_u32(extfilt);
+       if (nlmsg_len(cb->nlh) > sizeof(struct ifinfomsg)) {
+               struct nlattr *extfilt;
+
+               extfilt = nlmsg_find_attr(cb->nlh, sizeof(struct ifinfomsg),
+                                         IFLA_EXT_MASK);
+               if (extfilt) {
+                       if (nla_len(extfilt) < sizeof(filter_mask))
+                               return -EINVAL;
+
+                       filter_mask = nla_get_u32(extfilt);
+               }
+       }
 
        rcu_read_lock();
        for_each_netdev_rcu(net, dev) {
@@ -2798,6 +2805,9 @@ static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh)
        if (br_spec) {
                nla_for_each_nested(attr, br_spec, rem) {
                        if (nla_type(attr) == IFLA_BRIDGE_FLAGS) {
+                               if (nla_len(attr) < sizeof(flags))
+                                       return -EINVAL;
+
                                have_flags = true;
                                flags = nla_get_u16(attr);
                                break;
@@ -2868,6 +2878,9 @@ static int rtnl_bridge_dellink(struct sk_buff *skb, struct nlmsghdr *nlh)
        if (br_spec) {
                nla_for_each_nested(attr, br_spec, rem) {
                        if (nla_type(attr) == IFLA_BRIDGE_FLAGS) {
+                               if (nla_len(attr) < sizeof(flags))
+                                       return -EINVAL;
+
                                have_flags = true;
                                flags = nla_get_u16(attr);
                                break;
index c16615bfb61edd2a1dae9ef7935a3153d78dc4df..32e31c2996315770149b71b1e17837311d672a1e 100644 (file)
@@ -552,20 +552,13 @@ static void kfree_skbmem(struct sk_buff *skb)
        case SKB_FCLONE_CLONE:
                fclones = container_of(skb, struct sk_buff_fclones, skb2);
 
-               /* Warning : We must perform the atomic_dec_and_test() before
-                * setting skb->fclone back to SKB_FCLONE_FREE, otherwise
-                * skb_clone() could set clone_ref to 2 before our decrement.
-                * Anyway, if we are going to free the structure, no need to
-                * rewrite skb->fclone.
+               /* The clone portion is available for
+                * fast-cloning again.
                 */
-               if (atomic_dec_and_test(&fclones->fclone_ref)) {
+               skb->fclone = SKB_FCLONE_FREE;
+
+               if (atomic_dec_and_test(&fclones->fclone_ref))
                        kmem_cache_free(skbuff_fclone_cache, fclones);
-               } else {
-                       /* The clone portion is available for
-                        * fast-cloning again.
-                        */
-                       skb->fclone = SKB_FCLONE_FREE;
-               }
                break;
        }
 }
@@ -887,11 +880,7 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
        if (skb->fclone == SKB_FCLONE_ORIG &&
            n->fclone == SKB_FCLONE_FREE) {
                n->fclone = SKB_FCLONE_CLONE;
-               /* As our fastclone was free, clone_ref must be 1 at this point.
-                * We could use atomic_inc() here, but it is faster
-                * to set the final value.
-                */
-               atomic_set(&fclones->fclone_ref, 2);
+               atomic_inc(&fclones->fclone_ref);
        } else {
                if (skb_pfmemalloc(skb))
                        gfp_mask |= __GFP_MEMALLOC;
index ca11d283bbebe3ae02345ecd72cb022ae7c43667..93ea80196f0ec383cca46d28bf8c4c96d0310b25 100644 (file)
@@ -1080,13 +1080,13 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
        if (!app)
                return -EMSGSIZE;
 
-       spin_lock(&dcb_lock);
+       spin_lock_bh(&dcb_lock);
        list_for_each_entry(itr, &dcb_app_list, list) {
                if (itr->ifindex == netdev->ifindex) {
                        err = nla_put(skb, DCB_ATTR_IEEE_APP, sizeof(itr->app),
                                         &itr->app);
                        if (err) {
-                               spin_unlock(&dcb_lock);
+                               spin_unlock_bh(&dcb_lock);
                                return -EMSGSIZE;
                        }
                }
@@ -1097,7 +1097,7 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
        else
                dcbx = -EOPNOTSUPP;
 
-       spin_unlock(&dcb_lock);
+       spin_unlock_bh(&dcb_lock);
        nla_nest_end(skb, app);
 
        /* get peer info if available */
@@ -1234,7 +1234,7 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
        }
 
        /* local app */
-       spin_lock(&dcb_lock);
+       spin_lock_bh(&dcb_lock);
        app = nla_nest_start(skb, DCB_ATTR_CEE_APP_TABLE);
        if (!app)
                goto dcb_unlock;
@@ -1271,7 +1271,7 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
        else
                dcbx = -EOPNOTSUPP;
 
-       spin_unlock(&dcb_lock);
+       spin_unlock_bh(&dcb_lock);
 
        /* features flags */
        if (ops->getfeatcfg) {
@@ -1326,7 +1326,7 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
        return 0;
 
 dcb_unlock:
-       spin_unlock(&dcb_lock);
+       spin_unlock_bh(&dcb_lock);
 nla_put_failure:
        return err;
 }
@@ -1762,10 +1762,10 @@ u8 dcb_getapp(struct net_device *dev, struct dcb_app *app)
        struct dcb_app_type *itr;
        u8 prio = 0;
 
-       spin_lock(&dcb_lock);
+       spin_lock_bh(&dcb_lock);
        if ((itr = dcb_app_lookup(app, dev->ifindex, 0)))
                prio = itr->app.priority;
-       spin_unlock(&dcb_lock);
+       spin_unlock_bh(&dcb_lock);
 
        return prio;
 }
@@ -1789,7 +1789,7 @@ int dcb_setapp(struct net_device *dev, struct dcb_app *new)
        if (dev->dcbnl_ops->getdcbx)
                event.dcbx = dev->dcbnl_ops->getdcbx(dev);
 
-       spin_lock(&dcb_lock);
+       spin_lock_bh(&dcb_lock);
        /* Search for existing match and replace */
        if ((itr = dcb_app_lookup(new, dev->ifindex, 0))) {
                if (new->priority)
@@ -1804,7 +1804,7 @@ int dcb_setapp(struct net_device *dev, struct dcb_app *new)
        if (new->priority)
                err = dcb_app_add(new, dev->ifindex);
 out:
-       spin_unlock(&dcb_lock);
+       spin_unlock_bh(&dcb_lock);
        if (!err)
                call_dcbevent_notifiers(DCB_APP_EVENT, &event);
        return err;
@@ -1823,10 +1823,10 @@ u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app)
        struct dcb_app_type *itr;
        u8 prio = 0;
 
-       spin_lock(&dcb_lock);
+       spin_lock_bh(&dcb_lock);
        if ((itr = dcb_app_lookup(app, dev->ifindex, 0)))
                prio |= 1 << itr->app.priority;
-       spin_unlock(&dcb_lock);
+       spin_unlock_bh(&dcb_lock);
 
        return prio;
 }
@@ -1850,7 +1850,7 @@ int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new)
        if (dev->dcbnl_ops->getdcbx)
                event.dcbx = dev->dcbnl_ops->getdcbx(dev);
 
-       spin_lock(&dcb_lock);
+       spin_lock_bh(&dcb_lock);
        /* Search for existing match and abort if found */
        if (dcb_app_lookup(new, dev->ifindex, new->priority)) {
                err = -EEXIST;
@@ -1859,7 +1859,7 @@ int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new)
 
        err = dcb_app_add(new, dev->ifindex);
 out:
-       spin_unlock(&dcb_lock);
+       spin_unlock_bh(&dcb_lock);
        if (!err)
                call_dcbevent_notifiers(DCB_APP_EVENT, &event);
        return err;
@@ -1882,7 +1882,7 @@ int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del)
        if (dev->dcbnl_ops->getdcbx)
                event.dcbx = dev->dcbnl_ops->getdcbx(dev);
 
-       spin_lock(&dcb_lock);
+       spin_lock_bh(&dcb_lock);
        /* Search for existing match and remove it. */
        if ((itr = dcb_app_lookup(del, dev->ifindex, del->priority))) {
                list_del(&itr->list);
@@ -1890,7 +1890,7 @@ int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del)
                err = 0;
        }
 
-       spin_unlock(&dcb_lock);
+       spin_unlock_bh(&dcb_lock);
        if (!err)
                call_dcbevent_notifiers(DCB_APP_EVENT, &event);
        return err;
@@ -1902,12 +1902,12 @@ static void dcb_flushapp(void)
        struct dcb_app_type *app;
        struct dcb_app_type *tmp;
 
-       spin_lock(&dcb_lock);
+       spin_lock_bh(&dcb_lock);
        list_for_each_entry_safe(app, tmp, &dcb_app_list, list) {
                list_del(&app->list);
                kfree(app);
        }
-       spin_unlock(&dcb_lock);
+       spin_unlock_bh(&dcb_lock);
 }
 
 static int __init dcbnl_init(void)
index 8b7fe5b039068559a931b931529f02841cc13fe2..e67da4e6c3240bb20a7d8a03a3b579f7484f629e 100644 (file)
@@ -1386,6 +1386,17 @@ out:
        return pp;
 }
 
+int inet_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
+{
+       if (sk->sk_family == AF_INET)
+               return ip_recv_error(sk, msg, len, addr_len);
+#if IS_ENABLED(CONFIG_IPV6)
+       if (sk->sk_family == AF_INET6)
+               return pingv6_ops.ipv6_recv_error(sk, msg, len, addr_len);
+#endif
+       return -EINVAL;
+}
+
 static int inet_gro_complete(struct sk_buff *skb, int nhoff)
 {
        __be16 newlen = htons(skb->len - nhoff);
index f2e15738534d316ed0c50b8be2e1976fa03052c5..8f7bd56955b0dc35bb89e4fd0d3fe19fe9b53a47 100644 (file)
@@ -62,6 +62,10 @@ int __fib_lookup(struct net *net, struct flowi4 *flp, struct fib_result *res)
        else
                res->tclassid = 0;
 #endif
+
+       if (err == -ESRCH)
+               err = -ENETUNREACH;
+
        return err;
 }
 EXPORT_SYMBOL_GPL(__fib_lookup);
index fb70e3ecc3e4d58da5db9756db9b6da027369288..bb15d0e03d4f851d789734213814ed5359b59be1 100644 (file)
@@ -318,9 +318,7 @@ igmp_scount(struct ip_mc_list *pmc, int type, int gdeleted, int sdeleted)
        return scount;
 }
 
-#define igmp_skb_size(skb) (*(unsigned int *)((skb)->cb))
-
-static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
+static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu)
 {
        struct sk_buff *skb;
        struct rtable *rt;
@@ -330,6 +328,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
        struct flowi4 fl4;
        int hlen = LL_RESERVED_SPACE(dev);
        int tlen = dev->needed_tailroom;
+       unsigned int size = mtu;
 
        while (1) {
                skb = alloc_skb(size + hlen + tlen,
@@ -341,7 +340,6 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
                        return NULL;
        }
        skb->priority = TC_PRIO_CONTROL;
-       igmp_skb_size(skb) = size;
 
        rt = ip_route_output_ports(net, &fl4, NULL, IGMPV3_ALL_MCR, 0,
                                   0, 0,
@@ -354,6 +352,8 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
        skb_dst_set(skb, &rt->dst);
        skb->dev = dev;
 
+       skb->reserved_tailroom = skb_end_offset(skb) -
+                                min(mtu, skb_end_offset(skb));
        skb_reserve(skb, hlen);
 
        skb_reset_network_header(skb);
@@ -423,8 +423,7 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ip_mc_list *pmc,
        return skb;
 }
 
-#define AVAILABLE(skb) ((skb) ? ((skb)->dev ? igmp_skb_size(skb) - (skb)->len : \
-       skb_tailroom(skb)) : 0)
+#define AVAILABLE(skb) ((skb) ? skb_availroom(skb) : 0)
 
 static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc,
        int type, int gdeleted, int sdeleted)
index 3e861011e4a31e57b21c3fa507c178d3693a7970..1a7e979e80ba356f685ecfe020b98855f19db0a3 100644 (file)
@@ -528,6 +528,7 @@ static struct rtnl_link_ops vti_link_ops __read_mostly = {
        .validate       = vti_tunnel_validate,
        .newlink        = vti_newlink,
        .changelink     = vti_changelink,
+       .dellink        = ip_tunnel_dellink,
        .get_size       = vti_get_size,
        .fill_info      = vti_fill_info,
 };
index c1023c4459201ad63394606cab4b42fae61257aa..665de06561cd51e0933aa8436438b499d3c5066c 100644 (file)
@@ -24,6 +24,7 @@ static void nft_masq_ipv4_eval(const struct nft_expr *expr,
        struct nf_nat_range range;
        unsigned int verdict;
 
+       memset(&range, 0, sizeof(range));
        range.flags = priv->flags;
 
        verdict = nf_nat_masquerade_ipv4(pkt->skb, pkt->ops->hooknum,
index 57f7c98041394998fe390735aa5b8cd2602b3f90..5d740cccf69ec29d9778ddb0568c726266904ce9 100644 (file)
@@ -217,6 +217,8 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
                                             &ipv6_hdr(skb)->daddr))
                                continue;
 #endif
+               } else {
+                       continue;
                }
 
                if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)
@@ -853,16 +855,8 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        if (flags & MSG_OOB)
                goto out;
 
-       if (flags & MSG_ERRQUEUE) {
-               if (family == AF_INET) {
-                       return ip_recv_error(sk, msg, len, addr_len);
-#if IS_ENABLED(CONFIG_IPV6)
-               } else if (family == AF_INET6) {
-                       return pingv6_ops.ipv6_recv_error(sk, msg, len,
-                                                         addr_len);
-#endif
-               }
-       }
+       if (flags & MSG_ERRQUEUE)
+               return inet_recv_error(sk, msg, len, addr_len);
 
        skb = skb_recv_datagram(sk, flags, noblock, &err);
        if (!skb)
index 39ec0c379545afe07d6016c9180e9c408d22d4df..38c2bcb8dd5da4f2c8dede10942a1388fd3d9954 100644 (file)
@@ -1598,7 +1598,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        u32 urg_hole = 0;
 
        if (unlikely(flags & MSG_ERRQUEUE))
-               return ip_recv_error(sk, msg, len, addr_len);
+               return inet_recv_error(sk, msg, len, addr_len);
 
        if (sk_can_busy_loop(sk) && skb_queue_empty(&sk->sk_receive_queue) &&
            (sk->sk_state == TCP_ESTABLISHED))
index 88fa2d1606859de25419d0d45c3095f6d410d42b..d107ee246a1d32703ccc260309d52c3493927862 100644 (file)
@@ -5231,7 +5231,7 @@ slow_path:
        if (len < (th->doff << 2) || tcp_checksum_complete_user(sk, skb))
                goto csum_error;
 
-       if (!th->ack && !th->rst)
+       if (!th->ack && !th->rst && !th->syn)
                goto discard;
 
        /*
@@ -5650,7 +5650,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                        goto discard;
        }
 
-       if (!th->ack && !th->rst)
+       if (!th->ack && !th->rst && !th->syn)
                goto discard;
 
        if (!tcp_validate_incoming(sk, skb, th, 0))
index 9c7d7621466b1241f404a5ca11de809dcff2d02a..147be202429064d03b34405dba575c8d002b267c 100644 (file)
@@ -598,7 +598,10 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
        if (th->rst)
                return;
 
-       if (skb_rtable(skb)->rt_type != RTN_LOCAL)
+       /* If sk not NULL, it means we did a successful lookup and incoming
+        * route had to be correct. prequeue might have dropped our dst.
+        */
+       if (!sk && skb_rtable(skb)->rt_type != RTN_LOCAL)
                return;
 
        /* Swap the send and the receive. */
index 4564e1fca3eb42ab23c8370069417a456cdc76eb..0e32d2e1bdbfecabd3ae7e8ddb33a99f51cd7b51 100644 (file)
@@ -502,11 +502,11 @@ static int ip6gre_rcv(struct sk_buff *skb)
 
                skb->protocol = gre_proto;
                /* WCCP version 1 and 2 protocol decoding.
-                * - Change protocol to IP
+                * - Change protocol to IPv6
                 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
                 */
                if (flags == 0 && gre_proto == htons(ETH_P_WCCP)) {
-                       skb->protocol = htons(ETH_P_IP);
+                       skb->protocol = htons(ETH_P_IPV6);
                        if ((*(h + offset) & 0xF0) != 0x40)
                                offset += 4;
                }
index a071563a7e6e9c1f6d0fa9d8490c1d35ce89b3f7..01e12d0d8fcc9284403629fd17d7de010463d480 100644 (file)
@@ -69,7 +69,8 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
        int nhoff;
 
        if (unlikely(skb_shinfo(skb)->gso_type &
-                    ~(SKB_GSO_UDP |
+                    ~(SKB_GSO_TCPV4 |
+                      SKB_GSO_UDP |
                       SKB_GSO_DODGY |
                       SKB_GSO_TCP_ECN |
                       SKB_GSO_GRE |
index b04ed72c454247886d7d99ae5c9e36e949b48cd1..8db6c98fe21858f4b3f630af277a0137e438aa8d 100644 (file)
@@ -79,15 +79,13 @@ int udp_tunnel6_xmit_skb(struct socket *sock, struct dst_entry *dst,
        uh->source = src_port;
 
        uh->len = htons(skb->len);
-       uh->check = 0;
 
        memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
        IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED
                            | IPSKB_REROUTED);
        skb_dst_set(skb, dst);
 
-       udp6_set_csum(udp_get_no_check6_tx(sk), skb, &inet6_sk(sk)->saddr,
-                     &sk->sk_v6_daddr, skb->len);
+       udp6_set_csum(udp_get_no_check6_tx(sk), skb, saddr, daddr, skb->len);
 
        __skb_push(skb, sizeof(*ip6h));
        skb_reset_network_header(skb);
index 31089d153fd332136fcb9f89305ad7ab5bfb214d..bcda14de7f84822a17b382a6256e49b665ed7a83 100644 (file)
@@ -905,6 +905,15 @@ static int vti6_newlink(struct net *src_net, struct net_device *dev,
        return vti6_tnl_create2(dev);
 }
 
+static void vti6_dellink(struct net_device *dev, struct list_head *head)
+{
+       struct net *net = dev_net(dev);
+       struct vti6_net *ip6n = net_generic(net, vti6_net_id);
+
+       if (dev != ip6n->fb_tnl_dev)
+               unregister_netdevice_queue(dev, head);
+}
+
 static int vti6_changelink(struct net_device *dev, struct nlattr *tb[],
                           struct nlattr *data[])
 {
@@ -980,6 +989,7 @@ static struct rtnl_link_ops vti6_link_ops __read_mostly = {
        .setup          = vti6_dev_setup,
        .validate       = vti6_validate,
        .newlink        = vti6_newlink,
+       .dellink        = vti6_dellink,
        .changelink     = vti6_changelink,
        .get_size       = vti6_get_size,
        .fill_info      = vti6_fill_info,
@@ -1020,6 +1030,7 @@ static int __net_init vti6_init_net(struct net *net)
        if (!ip6n->fb_tnl_dev)
                goto err_alloc_dev;
        dev_net_set(ip6n->fb_tnl_dev, net);
+       ip6n->fb_tnl_dev->rtnl_link_ops = &vti6_link_ops;
 
        err = vti6_fb_tnl_dev_init(ip6n->fb_tnl_dev);
        if (err < 0)
index 0171f08325c3ff3991485297de4c532fe6992bf8..1a01d79b86980b1bc00d3692a061f614e7107773 100644 (file)
@@ -1439,6 +1439,10 @@ reg_pernet_fail:
 
 void ip6_mr_cleanup(void)
 {
+       rtnl_unregister(RTNL_FAMILY_IP6MR, RTM_GETROUTE);
+#ifdef CONFIG_IPV6_PIMSM_V2
+       inet6_del_protocol(&pim6_protocol, IPPROTO_PIM);
+#endif
        unregister_netdevice_notifier(&ip6_mr_notifier);
        unregister_pernet_subsys(&ip6mr_net_ops);
        kmem_cache_destroy(mrt_cachep);
index 9648de2b67458201ad9435b6972b05191c88c075..ed2c4e400b46bf762ff5379c3d62d69d940e5dd4 100644 (file)
@@ -1550,7 +1550,7 @@ static void ip6_mc_hdr(struct sock *sk, struct sk_buff *skb,
        hdr->daddr = *daddr;
 }
 
-static struct sk_buff *mld_newpack(struct inet6_dev *idev, int size)
+static struct sk_buff *mld_newpack(struct inet6_dev *idev, unsigned int mtu)
 {
        struct net_device *dev = idev->dev;
        struct net *net = dev_net(dev);
@@ -1561,13 +1561,13 @@ static struct sk_buff *mld_newpack(struct inet6_dev *idev, int size)
        const struct in6_addr *saddr;
        int hlen = LL_RESERVED_SPACE(dev);
        int tlen = dev->needed_tailroom;
+       unsigned int size = mtu + hlen + tlen;
        int err;
        u8 ra[8] = { IPPROTO_ICMPV6, 0,
                     IPV6_TLV_ROUTERALERT, 2, 0, 0,
                     IPV6_TLV_PADN, 0 };
 
        /* we assume size > sizeof(ra) here */
-       size += hlen + tlen;
        /* limit our allocations to order-0 page */
        size = min_t(int, size, SKB_MAX_ORDER(0, 0));
        skb = sock_alloc_send_skb(sk, size, 1, &err);
@@ -1576,6 +1576,8 @@ static struct sk_buff *mld_newpack(struct inet6_dev *idev, int size)
                return NULL;
 
        skb->priority = TC_PRIO_CONTROL;
+       skb->reserved_tailroom = skb_end_offset(skb) -
+                                min(mtu, skb_end_offset(skb));
        skb_reserve(skb, hlen);
 
        if (__ipv6_get_lladdr(idev, &addr_buf, IFA_F_TENTATIVE)) {
@@ -1690,8 +1692,7 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc,
        return skb;
 }
 
-#define AVAILABLE(skb) ((skb) ? ((skb)->dev ? (skb)->dev->mtu - (skb)->len : \
-       skb_tailroom(skb)) : 0)
+#define AVAILABLE(skb) ((skb) ? skb_availroom(skb) : 0)
 
 static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
        int type, int gdeleted, int sdeleted, int crsend)
index 8a7ac685076d91b18baf91e9ab386a98415ee009..529c119cbb14c9eff00c7a5fb63148ef0bc9f740 100644 (file)
@@ -25,6 +25,7 @@ static void nft_masq_ipv6_eval(const struct nft_expr *expr,
        struct nf_nat_range range;
        unsigned int verdict;
 
+       memset(&range, 0, sizeof(range));
        range.flags = priv->flags;
 
        verdict = nf_nat_masquerade_ipv6(pkt->skb, &range, pkt->out);
index ace29b60813cf8a1d7182ad2262cbcbd21810fa7..dc495ae2ead05aca0190bcab8c2d95b58beb2ac9 100644 (file)
@@ -903,7 +903,10 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
        if (th->rst)
                return;
 
-       if (!ipv6_unicast_destination(skb))
+       /* If sk not NULL, it means we did a successful lookup and incoming
+        * route had to be correct. prequeue might have dropped our dst.
+        */
+       if (!sk && !ipv6_unicast_destination(skb))
                return;
 
 #ifdef CONFIG_TCP_MD5SIG
index 91729b807c7d041ae379e89df335acefe5218635..1b095ca37aa46bd86a534a5d7eff4824d65b2ef2 100644 (file)
@@ -1764,6 +1764,7 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
        struct ipxhdr *ipx = NULL;
        struct sk_buff *skb;
        int copied, rc;
+       bool locked = true;
 
        lock_sock(sk);
        /* put the autobinding in */
@@ -1790,6 +1791,8 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
        if (sock_flag(sk, SOCK_ZAPPED))
                goto out;
 
+       release_sock(sk);
+       locked = false;
        skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
                                flags & MSG_DONTWAIT, &rc);
        if (!skb) {
@@ -1826,7 +1829,8 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
 out_free:
        skb_free_datagram(sk, skb);
 out:
-       release_sock(sk);
+       if (locked)
+               release_sock(sk);
        return rc;
 }
 
index ec24378caaafaf333152e856aa0e2e920ddbb13f..09d9caaec59112f40b060951ae16796388e2e741 100644 (file)
@@ -53,6 +53,9 @@ int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
                __aligned(__alignof__(struct aead_request));
        struct aead_request *aead_req = (void *) aead_req_data;
 
+       if (data_len == 0)
+               return -EINVAL;
+
        memset(aead_req, 0, sizeof(aead_req_data));
 
        sg_init_one(&pt, data, data_len);
index df90ce2db00c042a31bf3cd79dab3cfefcacbc35..408fd8ab4eef7eaf5f39d643644969a3943c1b3f 100644 (file)
@@ -252,19 +252,16 @@ minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u8 index,
        cur_thr = mi->groups[cur_group].rates[cur_idx].cur_tp;
        cur_prob = mi->groups[cur_group].rates[cur_idx].probability;
 
-       tmp_group = tp_list[j - 1] / MCS_GROUP_RATES;
-       tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES;
-       tmp_thr = mi->groups[tmp_group].rates[tmp_idx].cur_tp;
-       tmp_prob = mi->groups[tmp_group].rates[tmp_idx].probability;
-
-       while (j > 0 && (cur_thr > tmp_thr ||
-             (cur_thr == tmp_thr && cur_prob > tmp_prob))) {
-               j--;
+       do {
                tmp_group = tp_list[j - 1] / MCS_GROUP_RATES;
                tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES;
                tmp_thr = mi->groups[tmp_group].rates[tmp_idx].cur_tp;
                tmp_prob = mi->groups[tmp_group].rates[tmp_idx].probability;
-       }
+               if (cur_thr < tmp_thr ||
+                   (cur_thr == tmp_thr && cur_prob <= tmp_prob))
+                       break;
+               j--;
+       } while (j > 0);
 
        if (j < MAX_THR_RATES - 1) {
                memmove(&tp_list[j + 1], &tp_list[j], (sizeof(*tp_list) *
index 86f9d76b1464b1b0d5e8b5fc9f9c0c129713bd57..d259da3ce67a6b18f6e4a345a5729876e373efc0 100644 (file)
@@ -1863,6 +1863,12 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
        if (*op < IP_SET_OP_VERSION) {
                /* Check the version at the beginning of operations */
                struct ip_set_req_version *req_version = data;
+
+               if (*len < sizeof(struct ip_set_req_version)) {
+                       ret = -EINVAL;
+                       goto done;
+               }
+
                if (req_version->version != IPSET_PROTOCOL) {
                        ret = -EPROTO;
                        goto done;
index 437a3663ad0346e13cfbc0017be20b4bad73c218..bd90bf8107dacb4e7e0683110bb2146faf168b26 100644 (file)
@@ -846,6 +846,8 @@ ip_vs_prepare_tunneled_skb(struct sk_buff *skb, int skb_af,
                new_skb = skb_realloc_headroom(skb, max_headroom);
                if (!new_skb)
                        goto error;
+               if (skb->sk)
+                       skb_set_owner_w(new_skb, skb->sk);
                consume_skb(skb);
                skb = new_skb;
        }
index 11ab4b078f3bb68323b1f050f3a1d5e83d271f36..66e8425dbfe77b11e41eb7c97c68f3778ee0c9e7 100644 (file)
@@ -3484,13 +3484,8 @@ static void nft_chain_commit_update(struct nft_trans *trans)
        }
 }
 
-/* Schedule objects for release via rcu to make sure no packets are accesing
- * removed rules.
- */
-static void nf_tables_commit_release_rcu(struct rcu_head *rt)
+static void nf_tables_commit_release(struct nft_trans *trans)
 {
-       struct nft_trans *trans = container_of(rt, struct nft_trans, rcu_head);
-
        switch (trans->msg_type) {
        case NFT_MSG_DELTABLE:
                nf_tables_table_destroy(&trans->ctx);
@@ -3612,10 +3607,11 @@ static int nf_tables_commit(struct sk_buff *skb)
                }
        }
 
+       synchronize_rcu();
+
        list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
                list_del(&trans->list);
-               trans->ctx.nla = NULL;
-               call_rcu(&trans->rcu_head, nf_tables_commit_release_rcu);
+               nf_tables_commit_release(trans);
        }
 
        nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
@@ -3623,13 +3619,8 @@ static int nf_tables_commit(struct sk_buff *skb)
        return 0;
 }
 
-/* Schedule objects for release via rcu to make sure no packets are accesing
- * aborted rules.
- */
-static void nf_tables_abort_release_rcu(struct rcu_head *rt)
+static void nf_tables_abort_release(struct nft_trans *trans)
 {
-       struct nft_trans *trans = container_of(rt, struct nft_trans, rcu_head);
-
        switch (trans->msg_type) {
        case NFT_MSG_NEWTABLE:
                nf_tables_table_destroy(&trans->ctx);
@@ -3725,11 +3716,12 @@ static int nf_tables_abort(struct sk_buff *skb)
                }
        }
 
+       synchronize_rcu();
+
        list_for_each_entry_safe_reverse(trans, next,
                                         &net->nft.commit_list, list) {
                list_del(&trans->list);
-               trans->ctx.nla = NULL;
-               call_rcu(&trans->rcu_head, nf_tables_abort_release_rcu);
+               nf_tables_abort_release(trans);
        }
 
        return 0;
index 6c5a915cfa758bb4d8187dac9dc606201e99b458..13c2e17bbe279e6660a0a04fc804a6e1dd0a7707 100644 (file)
@@ -47,6 +47,8 @@ static const int nfnl_group2type[NFNLGRP_MAX+1] = {
        [NFNLGRP_CONNTRACK_EXP_NEW]     = NFNL_SUBSYS_CTNETLINK_EXP,
        [NFNLGRP_CONNTRACK_EXP_UPDATE]  = NFNL_SUBSYS_CTNETLINK_EXP,
        [NFNLGRP_CONNTRACK_EXP_DESTROY] = NFNL_SUBSYS_CTNETLINK_EXP,
+       [NFNLGRP_NFTABLES]              = NFNL_SUBSYS_NFTABLES,
+       [NFNLGRP_ACCT_QUOTA]            = NFNL_SUBSYS_ACCT,
 };
 
 void nfnl_lock(__u8 subsys_id)
@@ -464,7 +466,12 @@ static void nfnetlink_rcv(struct sk_buff *skb)
 static int nfnetlink_bind(int group)
 {
        const struct nfnetlink_subsystem *ss;
-       int type = nfnl_group2type[group];
+       int type;
+
+       if (group <= NFNLGRP_NONE || group > NFNLGRP_MAX)
+               return -EINVAL;
+
+       type = nfnl_group2type[group];
 
        rcu_read_lock();
        ss = nfnetlink_get_subsys(type);
@@ -514,6 +521,9 @@ static int __init nfnetlink_init(void)
 {
        int i;
 
+       for (i = NFNLGRP_NONE + 1; i <= NFNLGRP_MAX; i++)
+               BUG_ON(nfnl_group2type[i] == NFNL_SUBSYS_NONE);
+
        for (i=0; i<NFNL_SUBSYS_COUNT; i++)
                mutex_init(&table[i].mutex);
 
index 9d6d6f60a80fc6b23da9bb140c90e085a4fa675a..265e190f22187d83de1a9ed07913ef153cf1f03f 100644 (file)
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <net/netfilter/nf_tables.h>
 
-static const struct {
-       const char      *name;
-       u8              type;
-} table_to_chaintype[] = {
-       { "filter",     NFT_CHAIN_T_DEFAULT },
-       { "raw",        NFT_CHAIN_T_DEFAULT },
-       { "security",   NFT_CHAIN_T_DEFAULT },
-       { "mangle",     NFT_CHAIN_T_ROUTE },
-       { "nat",        NFT_CHAIN_T_NAT },
-       { },
-};
-
-static int nft_compat_table_to_chaintype(const char *table)
-{
-       int i;
-
-       for (i = 0; table_to_chaintype[i].name != NULL; i++) {
-               if (strcmp(table_to_chaintype[i].name, table) == 0)
-                       return table_to_chaintype[i].type;
-       }
-
-       return -1;
-}
-
 static int nft_compat_chain_validate_dependency(const char *tablename,
                                                const struct nft_chain *chain)
 {
-       enum nft_chain_type type;
        const struct nft_base_chain *basechain;
 
        if (!tablename || !(chain->flags & NFT_BASE_CHAIN))
                return 0;
 
-       type = nft_compat_table_to_chaintype(tablename);
-       if (type < 0)
-               return -EINVAL;
-
        basechain = nft_base_chain(chain);
-       if (basechain->type->type != type)
+       if (strcmp(tablename, "nat") == 0 &&
+           basechain->type->type != NFT_CHAIN_T_NAT)
                return -EINVAL;
 
        return 0;
@@ -117,7 +89,7 @@ nft_target_set_tgchk_param(struct xt_tgchk_param *par,
                           struct xt_target *target, void *info,
                           union nft_entry *entry, u8 proto, bool inv)
 {
-       par->net        = &init_net;
+       par->net        = ctx->net;
        par->table      = ctx->table->name;
        switch (ctx->afi->family) {
        case AF_INET:
@@ -324,7 +296,7 @@ nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
                          struct xt_match *match, void *info,
                          union nft_entry *entry, u8 proto, bool inv)
 {
-       par->net        = &init_net;
+       par->net        = ctx->net;
        par->table      = ctx->table->name;
        switch (ctx->afi->family) {
        case AF_INET:
@@ -374,7 +346,7 @@ nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
        union nft_entry e = {};
        int ret;
 
-       ret = nft_compat_chain_validate_dependency(match->name, ctx->chain);
+       ret = nft_compat_chain_validate_dependency(match->table, ctx->chain);
        if (ret < 0)
                goto err;
 
@@ -448,7 +420,7 @@ static int nft_match_validate(const struct nft_ctx *ctx,
                if (!(hook_mask & match->hooks))
                        return -EINVAL;
 
-               ret = nft_compat_chain_validate_dependency(match->name,
+               ret = nft_compat_chain_validate_dependency(match->table,
                                                           ctx->chain);
                if (ret < 0)
                        return ret;
index 006886dbee36b075fc7054ec1ddc87781a75d739..8c4229b11c34c617a81e58dcdb1a4a6034fd064c 100644 (file)
@@ -246,11 +246,11 @@ static void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto,
 {
        int transport_len = skb->len - skb_transport_offset(skb);
 
-       if (l4_proto == IPPROTO_TCP) {
+       if (l4_proto == NEXTHDR_TCP) {
                if (likely(transport_len >= sizeof(struct tcphdr)))
                        inet_proto_csum_replace16(&tcp_hdr(skb)->check, skb,
                                                  addr, new_addr, 1);
-       } else if (l4_proto == IPPROTO_UDP) {
+       } else if (l4_proto == NEXTHDR_UDP) {
                if (likely(transport_len >= sizeof(struct udphdr))) {
                        struct udphdr *uh = udp_hdr(skb);
 
@@ -261,6 +261,10 @@ static void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto,
                                        uh->check = CSUM_MANGLED_0;
                        }
                }
+       } else if (l4_proto == NEXTHDR_ICMP) {
+               if (likely(transport_len >= sizeof(struct icmp6hdr)))
+                       inet_proto_csum_replace16(&icmp6_hdr(skb)->icmp6_cksum,
+                                                 skb, addr, new_addr, 1);
        }
 }
 
@@ -722,8 +726,6 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
 
                case OVS_ACTION_ATTR_SAMPLE:
                        err = sample(dp, skb, key, a);
-                       if (unlikely(err)) /* skb already freed. */
-                               return err;
                        break;
                }
 
index e6d7255183eba31267ec29705441a019681ca617..f9e556b5608650e490ad1608f5a28280f55d3d08 100644 (file)
@@ -1265,7 +1265,7 @@ static size_t ovs_dp_cmd_msg_size(void)
        return msgsize;
 }
 
-/* Called with ovs_mutex or RCU read lock. */
+/* Called with ovs_mutex. */
 static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb,
                                u32 portid, u32 seq, u32 flags, u8 cmd)
 {
@@ -1555,7 +1555,7 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
        if (!reply)
                return -ENOMEM;
 
-       rcu_read_lock();
+       ovs_lock();
        dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
        if (IS_ERR(dp)) {
                err = PTR_ERR(dp);
@@ -1564,12 +1564,12 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
        err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
                                   info->snd_seq, 0, OVS_DP_CMD_NEW);
        BUG_ON(err < 0);
-       rcu_read_unlock();
+       ovs_unlock();
 
        return genlmsg_reply(reply, info);
 
 err_unlock_free:
-       rcu_read_unlock();
+       ovs_unlock();
        kfree_skb(reply);
        return err;
 }
@@ -1581,8 +1581,8 @@ static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
        int skip = cb->args[0];
        int i = 0;
 
-       rcu_read_lock();
-       list_for_each_entry_rcu(dp, &ovs_net->dps, list_node) {
+       ovs_lock();
+       list_for_each_entry(dp, &ovs_net->dps, list_node) {
                if (i >= skip &&
                    ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).portid,
                                         cb->nlh->nlmsg_seq, NLM_F_MULTI,
@@ -1590,7 +1590,7 @@ static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
                        break;
                i++;
        }
-       rcu_read_unlock();
+       ovs_unlock();
 
        cb->args[0] = i;
 
index 939bcb32100fe861b4ad94255d191ee281f83ed3..089b195c064ae56445b458e52e0dcaefa90b615c 100644 (file)
@@ -145,7 +145,7 @@ static bool match_validate(const struct sw_flow_match *match,
        if (match->key->eth.type == htons(ETH_P_ARP)
                        || match->key->eth.type == htons(ETH_P_RARP)) {
                key_expected |= 1 << OVS_KEY_ATTR_ARP;
-               if (match->mask && (match->mask->key.eth.type == htons(0xffff)))
+               if (match->mask && (match->mask->key.tp.src == htons(0xff)))
                        mask_allowed |= 1 << OVS_KEY_ATTR_ARP;
        }
 
@@ -689,6 +689,13 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs,
                                ipv6_key->ipv6_frag, OVS_FRAG_TYPE_MAX);
                        return -EINVAL;
                }
+
+               if (!is_mask && ipv6_key->ipv6_label & htonl(0xFFF00000)) {
+                       OVS_NLERR("IPv6 flow label %x is out of range (max=%x).\n",
+                                 ntohl(ipv6_key->ipv6_label), (1 << 20) - 1);
+                       return -EINVAL;
+               }
+
                SW_FLOW_KEY_PUT(match, ipv6.label,
                                ipv6_key->ipv6_label, is_mask);
                SW_FLOW_KEY_PUT(match, ip.proto,
index 87d20f48ff06195766e8ecd20a3fcfae5ccae690..07c04a841ba09c5ee5b0bc7718d4e6c87ac561e1 100644 (file)
@@ -378,7 +378,7 @@ static void unregister_prot_hook(struct sock *sk, bool sync)
                __unregister_prot_hook(sk, sync);
 }
 
-static inline __pure struct page *pgv_to_page(void *addr)
+static inline struct page * __pure pgv_to_page(void *addr)
 {
        if (is_vmalloc_addr(addr))
                return vmalloc_to_page(addr);
index 3f959c681885ba41ccdf6300bb27a35745ec11be..f9c052d508f008c4fb74567ea8cbad13f305d497 100644 (file)
@@ -1019,17 +1019,12 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
        xid = *p++;
        calldir = *p;
 
-       if (bc_xprt)
-               req = xprt_lookup_rqst(bc_xprt, xid);
-
-       if (!req) {
-               printk(KERN_NOTICE
-                       "%s: Got unrecognized reply: "
-                       "calldir 0x%x xpt_bc_xprt %p xid %08x\n",
-                       __func__, ntohl(calldir),
-                       bc_xprt, ntohl(xid));
+       if (!bc_xprt)
                return -EAGAIN;
-       }
+       spin_lock_bh(&bc_xprt->transport_lock);
+       req = xprt_lookup_rqst(bc_xprt, xid);
+       if (!req)
+               goto unlock_notfound;
 
        memcpy(&req->rq_private_buf, &req->rq_rcv_buf, sizeof(struct xdr_buf));
        /*
@@ -1040,11 +1035,21 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
        dst = &req->rq_private_buf.head[0];
        src = &rqstp->rq_arg.head[0];
        if (dst->iov_len < src->iov_len)
-               return -EAGAIN; /* whatever; just giving up. */
+               goto unlock_eagain; /* whatever; just giving up. */
        memcpy(dst->iov_base, src->iov_base, src->iov_len);
        xprt_complete_rqst(req->rq_task, rqstp->rq_arg.len);
        rqstp->rq_arg.len = 0;
+       spin_unlock_bh(&bc_xprt->transport_lock);
        return 0;
+unlock_notfound:
+       printk(KERN_NOTICE
+               "%s: Got unrecognized reply: "
+               "calldir 0x%x xpt_bc_xprt %p xid %08x\n",
+               __func__, ntohl(calldir),
+               bc_xprt, ntohl(xid));
+unlock_eagain:
+       spin_unlock_bh(&bc_xprt->transport_lock);
+       return -EAGAIN;
 }
 
 static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len)
index 42ded997b223b7ece3d8535000d4defeea2ba8f5..c6ff94ab1ad65a883e5b969437d05afb837e1a02 100644 (file)
@@ -216,6 +216,8 @@ static char *snd_pcm_format_names[] = {
        FORMAT(DSD_U8),
        FORMAT(DSD_U16_LE),
        FORMAT(DSD_U32_LE),
+       FORMAT(DSD_U16_BE),
+       FORMAT(DSD_U32_BE),
 };
 
 const char *snd_pcm_format_name(snd_pcm_format_t format)
index ae7a0feb3b76001f54555187c19343bce352f0c8..ebe8444de6c6ea8f44a5cacfb39b963939d9880d 100644 (file)
@@ -152,6 +152,14 @@ static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
                .width = 32, .phys = 32, .le = 1, .signd = 0,
                .silence = { 0x69, 0x69, 0x69, 0x69 },
        },
+       [SNDRV_PCM_FORMAT_DSD_U16_BE] = {
+               .width = 16, .phys = 16, .le = 0, .signd = 0,
+               .silence = { 0x69, 0x69 },
+       },
+       [SNDRV_PCM_FORMAT_DSD_U32_BE] = {
+               .width = 32, .phys = 32, .le = 0, .signd = 0,
+               .silence = { 0x69, 0x69, 0x69, 0x69 },
+       },
        /* FIXME: the following three formats are not defined properly yet */
        [SNDRV_PCM_FORMAT_MPEG] = {
                .le = -1, .signd = -1,
index 16660f312043a71fac284dd7948baab3491d05f3..48b6c5a3884f3b1ed729d542fd286ba2840a938b 100644 (file)
@@ -298,7 +298,8 @@ enum {
 
 /* quirks for ATI/AMD HDMI */
 #define AZX_DCAPS_PRESET_ATI_HDMI \
-       (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB)
+       (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB|\
+        AZX_DCAPS_NO_MSI64)
 
 /* quirks for Nvidia */
 #define AZX_DCAPS_PRESET_NVIDIA \
@@ -1486,6 +1487,7 @@ static int azx_first_init(struct azx *chip)
        struct snd_card *card = chip->card;
        int err;
        unsigned short gcap;
+       unsigned int dma_bits = 64;
 
 #if BITS_PER_LONG != 64
        /* Fix up base address on ULI M5461 */
@@ -1509,9 +1511,14 @@ static int azx_first_init(struct azx *chip)
                return -ENXIO;
        }
 
-       if (chip->msi)
+       if (chip->msi) {
+               if (chip->driver_caps & AZX_DCAPS_NO_MSI64) {
+                       dev_dbg(card->dev, "Disabling 64bit MSI\n");
+                       pci->no_64bit_msi = true;
+               }
                if (pci_enable_msi(pci) < 0)
                        chip->msi = 0;
+       }
 
        if (azx_acquire_irq(chip, 0) < 0)
                return -EBUSY;
@@ -1522,9 +1529,14 @@ static int azx_first_init(struct azx *chip)
        gcap = azx_readw(chip, GCAP);
        dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap);
 
+       /* AMD devices support 40 or 48bit DMA, take the safe one */
+       if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
+               dma_bits = 40;
+
        /* disable SB600 64bit support for safety */
        if (chip->pci->vendor == PCI_VENDOR_ID_ATI) {
                struct pci_dev *p_smbus;
+               dma_bits = 40;
                p_smbus = pci_get_device(PCI_VENDOR_ID_ATI,
                                         PCI_DEVICE_ID_ATI_SBX00_SMBUS,
                                         NULL);
@@ -1554,9 +1566,11 @@ static int azx_first_init(struct azx *chip)
        }
 
        /* allow 64bit DMA address if supported by H/W */
-       if ((gcap & AZX_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
-               pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64));
-       else {
+       if (!(gcap & AZX_GCAP_64OK))
+               dma_bits = 32;
+       if (!pci_set_dma_mask(pci, DMA_BIT_MASK(dma_bits))) {
+               pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(dma_bits));
+       } else {
                pci_set_dma_mask(pci, DMA_BIT_MASK(32));
                pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32));
        }
index 949cd437eeb264798aec5d9b2f5c5e61a87fc294..5016014e57f2f1dc65f68d5b71db8d12f065493f 100644 (file)
@@ -171,6 +171,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 #define AZX_DCAPS_PM_RUNTIME   (1 << 26)       /* runtime PM support */
 #define AZX_DCAPS_I915_POWERWELL (1 << 27)     /* HSW i915 powerwell support */
 #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28)  /* CORBRP clears itself after reset */
+#define AZX_DCAPS_NO_MSI64      (1 << 29)      /* Stick to 32-bit MSIs */
 
 /* HD Audio class code */
 #define PCI_CLASS_MULTIMEDIA_HD_AUDIO  0x0403
index 172395465e8a63963d096ec29f3ee04f7bfe5948..14f16be3f3747a3c72f1ba2938d2a1ca3f8007b2 100644 (file)
@@ -4520,6 +4520,8 @@ static const struct hda_fixup alc269_fixups[] = {
        [ALC269_FIXUP_HEADSET_MODE] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_headset_mode,
+               .chained = true,
+               .chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED
        },
        [ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
                .type = HDA_FIXUP_FUNC,
@@ -4709,6 +4711,8 @@ static const struct hda_fixup alc269_fixups[] = {
        [ALC255_FIXUP_HEADSET_MODE] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_headset_mode_alc255,
+               .chained = true,
+               .chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED
        },
        [ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
                .type = HDA_FIXUP_FUNC,
@@ -4744,8 +4748,6 @@ static const struct hda_fixup alc269_fixups[] = {
        [ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_dell_wmi,
-               .chained_before = true,
-               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
        },
        [ALC282_FIXUP_ASPIRE_V5_PINS] = {
                .type = HDA_FIXUP_PINS,
@@ -4783,10 +4785,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x05f4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0610, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED),
        SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
        SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
-       SND_PCI_QUIRK(0x1028, 0x061f, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED),
        SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK),
        SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
@@ -4818,7 +4818,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2246, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2253, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2254, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x2255, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
index cee51ae177c1e219325231eb517b91784ac258fe..c40428f25ba5c9b9b3d2e5e657a71020702dc12b 100644 (file)
@@ -46,6 +46,7 @@ static struct i2c_driver cs42l51_i2c_driver = {
        .driver = {
                .name = "cs42l51",
                .owner = THIS_MODULE,
+               .of_match_table = cs42l51_of_match,
        },
        .probe = cs42l51_i2c_probe,
        .remove = cs42l51_i2c_remove,
index 09488d97de60d040bbdb37edfa3a94a999930633..669c38fc303468d51dd6bbd3dfa16e935c030e8c 100644 (file)
@@ -558,11 +558,13 @@ error:
 }
 EXPORT_SYMBOL_GPL(cs42l51_probe);
 
-static const struct of_device_id cs42l51_of_match[] = {
+const struct of_device_id cs42l51_of_match[] = {
        { .compatible = "cirrus,cs42l51", },
        { }
 };
 MODULE_DEVICE_TABLE(of, cs42l51_of_match);
+EXPORT_SYMBOL_GPL(cs42l51_of_match);
+
 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
 MODULE_LICENSE("GPL");
index 8c55bf384bc65189545807d9ce9278d6c66670f2..0ca805492ac4b77d110dc24b378845fb5b3768a6 100644 (file)
@@ -22,6 +22,7 @@ struct device;
 
 extern const struct regmap_config cs42l51_regmap;
 int cs42l51_probe(struct device *dev, struct regmap *regmap);
+extern const struct of_device_id cs42l51_of_match[];
 
 #define CS42L51_CHIP_ID                        0x1B
 #define CS42L51_CHIP_REV_A             0x00
index aae410d122ee1f8f7cb99fbd416fd02c0f17fdfd..2d05b5d3a6ce7fdc3531f5c322853dbb1a0ca63e 100644 (file)
@@ -19,7 +19,7 @@
 #include "es8328.h"
 
 static const struct i2c_device_id es8328_id[] = {
-       { "everest,es8328", 0 },
+       { "es8328", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, es8328_id);
index d519294f57c79c289784f9a71bb43d7bf51dc7e9..1229554f1464d1e1c37a1d82d227a5a6347e377d 100644 (file)
@@ -1941,13 +1941,13 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
         *               0x02 (when master clk is 20MHz to 40MHz)..
         *               0x03 (when master clk is 40MHz to 60MHz)..
         */
-       if ((freq >= 10000000) && (freq < 20000000)) {
+       if ((freq >= 10000000) && (freq <= 20000000)) {
                snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
                        M98090_PSCLK_DIV1);
-       } else if ((freq >= 20000000) && (freq < 40000000)) {
+       } else if ((freq > 20000000) && (freq <= 40000000)) {
                snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
                        M98090_PSCLK_DIV2);
-       } else if ((freq >= 40000000) && (freq < 60000000)) {
+       } else if ((freq > 40000000) && (freq <= 60000000)) {
                snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
                        M98090_PSCLK_DIV4);
        } else {
index 3fb83bf09768347f1bcd469d2be9be4b56ea62e2..d16331e0b64d4532647b5f4eb4d4abe58a4d66ec 100644 (file)
@@ -139,6 +139,7 @@ static const struct reg_default rt5645_reg[] = {
        { 0x76, 0x000a },
        { 0x77, 0x0c00 },
        { 0x78, 0x0000 },
+       { 0x79, 0x0123 },
        { 0x80, 0x0000 },
        { 0x81, 0x0000 },
        { 0x82, 0x0000 },
@@ -334,6 +335,7 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg)
        case RT5645_DMIC_CTRL2:
        case RT5645_TDM_CTRL_1:
        case RT5645_TDM_CTRL_2:
+       case RT5645_TDM_CTRL_3:
        case RT5645_GLB_CLK:
        case RT5645_PLL_CTRL1:
        case RT5645_PLL_CTRL2:
index ba9d9b4d485783c80efa30e13e3218f1fec7742e..9bd8b4f633032c713a432ca3af1bc38aa3c81f16 100644 (file)
@@ -100,18 +100,18 @@ static const struct reg_default rt5670_reg[] = {
        { 0x4c, 0x5380 },
        { 0x4f, 0x0073 },
        { 0x52, 0x00d3 },
-       { 0x53, 0xf0f0 },
+       { 0x53, 0xf000 },
        { 0x61, 0x0000 },
        { 0x62, 0x0001 },
        { 0x63, 0x00c3 },
        { 0x64, 0x0000 },
-       { 0x65, 0x0000 },
+       { 0x65, 0x0001 },
        { 0x66, 0x0000 },
        { 0x6f, 0x8000 },
        { 0x70, 0x8000 },
        { 0x71, 0x8000 },
        { 0x72, 0x8000 },
-       { 0x73, 0x1110 },
+       { 0x73, 0x7770 },
        { 0x74, 0x0e00 },
        { 0x75, 0x1505 },
        { 0x76, 0x0015 },
@@ -125,21 +125,21 @@ static const struct reg_default rt5670_reg[] = {
        { 0x83, 0x0000 },
        { 0x84, 0x0000 },
        { 0x85, 0x0000 },
-       { 0x86, 0x0008 },
+       { 0x86, 0x0004 },
        { 0x87, 0x0000 },
        { 0x88, 0x0000 },
        { 0x89, 0x0000 },
        { 0x8a, 0x0000 },
        { 0x8b, 0x0000 },
-       { 0x8c, 0x0007 },
+       { 0x8c, 0x0003 },
        { 0x8d, 0x0000 },
        { 0x8e, 0x0004 },
        { 0x8f, 0x1100 },
        { 0x90, 0x0646 },
        { 0x91, 0x0c06 },
        { 0x93, 0x0000 },
-       { 0x94, 0x0000 },
-       { 0x95, 0x0000 },
+       { 0x94, 0x1270 },
+       { 0x95, 0x1000 },
        { 0x97, 0x0000 },
        { 0x98, 0x0000 },
        { 0x99, 0x0000 },
@@ -150,11 +150,11 @@ static const struct reg_default rt5670_reg[] = {
        { 0x9e, 0x0400 },
        { 0xae, 0x7000 },
        { 0xaf, 0x0000 },
-       { 0xb0, 0x6000 },
+       { 0xb0, 0x7000 },
        { 0xb1, 0x0000 },
        { 0xb2, 0x0000 },
        { 0xb3, 0x001f },
-       { 0xb4, 0x2206 },
+       { 0xb4, 0x220c },
        { 0xb5, 0x1f00 },
        { 0xb6, 0x0000 },
        { 0xb7, 0x0000 },
@@ -171,25 +171,25 @@ static const struct reg_default rt5670_reg[] = {
        { 0xcf, 0x1813 },
        { 0xd0, 0x0690 },
        { 0xd1, 0x1c17 },
-       { 0xd3, 0xb320 },
+       { 0xd3, 0xa220 },
        { 0xd4, 0x0000 },
        { 0xd6, 0x0400 },
        { 0xd9, 0x0809 },
        { 0xda, 0x0000 },
        { 0xdb, 0x0001 },
        { 0xdc, 0x0049 },
-       { 0xdd, 0x0009 },
+       { 0xdd, 0x0024 },
        { 0xe6, 0x8000 },
        { 0xe7, 0x0000 },
-       { 0xec, 0xb300 },
+       { 0xec, 0xa200 },
        { 0xed, 0x0000 },
-       { 0xee, 0xb300 },
+       { 0xee, 0xa200 },
        { 0xef, 0x0000 },
        { 0xf8, 0x0000 },
        { 0xf9, 0x0000 },
        { 0xfa, 0x8010 },
        { 0xfb, 0x0033 },
-       { 0xfc, 0x0080 },
+       { 0xfc, 0x0100 },
 };
 
 static bool rt5670_volatile_register(struct device *dev, unsigned int reg)
@@ -1877,6 +1877,10 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
        { "DAC1 MIXR", "DAC1 Switch", "DAC1 R Mux" },
        { "DAC1 MIXR", NULL, "DAC Stereo1 Filter" },
 
+       { "DAC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll },
+       { "DAC Mono Left Filter", NULL, "PLL1", is_sys_clk_from_pll },
+       { "DAC Mono Right Filter", NULL, "PLL1", is_sys_clk_from_pll },
+
        { "DAC MIX", NULL, "DAC1 MIXL" },
        { "DAC MIX", NULL, "DAC1 MIXR" },
 
@@ -1926,14 +1930,10 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
 
        { "DAC L1", NULL, "DAC L1 Power" },
        { "DAC L1", NULL, "Stereo DAC MIXL" },
-       { "DAC L1", NULL, "PLL1", is_sys_clk_from_pll },
        { "DAC R1", NULL, "DAC R1 Power" },
        { "DAC R1", NULL, "Stereo DAC MIXR" },
-       { "DAC R1", NULL, "PLL1", is_sys_clk_from_pll },
        { "DAC L2", NULL, "Mono DAC MIXL" },
-       { "DAC L2", NULL, "PLL1", is_sys_clk_from_pll },
        { "DAC R2", NULL, "Mono DAC MIXR" },
-       { "DAC R2", NULL, "PLL1", is_sys_clk_from_pll },
 
        { "OUT MIXL", "BST1 Switch", "BST1" },
        { "OUT MIXL", "INL Switch", "INL VOL" },
index 6bb77d76561b8964303275955d1e1beb579ba859..dab9b15304af829a510742ec4a4827bdca90a453 100644 (file)
@@ -1299,8 +1299,7 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
 
        /* enable small pop, introduce 400ms delay in turning off */
        snd_soc_update_bits(codec, SGTL5000_CHIP_REF_CTRL,
-                               SGTL5000_SMALL_POP,
-                               SGTL5000_SMALL_POP);
+                               SGTL5000_SMALL_POP, 1);
 
        /* disable short cut detector */
        snd_soc_write(codec, SGTL5000_CHIP_SHORT_CTRL, 0);
index 2f8c88931f690579f86d497d03ef7327a156a94c..bd7a344bf8c517edf69af2fda9e06e08488e47e0 100644 (file)
 #define SGTL5000_BIAS_CTRL_MASK                        0x000e
 #define SGTL5000_BIAS_CTRL_SHIFT               1
 #define SGTL5000_BIAS_CTRL_WIDTH               3
-#define SGTL5000_SMALL_POP                     0x0001
+#define SGTL5000_SMALL_POP                     0
 
 /*
  * SGTL5000_CHIP_MIC_CTRL
index f412a9911a75d2fe531930f6a0108fb977c41e77..67124783558a5374b547f26d30d1ccc2bdc16ae4 100644 (file)
@@ -1355,6 +1355,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
                          file, blocks, pos - firmware->size);
 
 out_fw:
+       regmap_async_complete(regmap);
        release_firmware(firmware);
        wm_adsp_buf_free(&buf_list);
 out:
index ed866e9a2928c4ca5415571fc757f6ba588b636f..9deabdd2b1a29adf3d27335557cd1cc23fee11f4 100644 (file)
@@ -684,12 +684,38 @@ static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg)
        }
 }
 
+static struct reg_default fsl_asrc_reg[] = {
+       { REG_ASRCTR, 0x0000 }, { REG_ASRIER, 0x0000 },
+       { REG_ASRCNCR, 0x0000 }, { REG_ASRCFG, 0x0000 },
+       { REG_ASRCSR, 0x0000 }, { REG_ASRCDR1, 0x0000 },
+       { REG_ASRCDR2, 0x0000 }, { REG_ASRSTR, 0x0000 },
+       { REG_ASRRA, 0x0000 }, { REG_ASRRB, 0x0000 },
+       { REG_ASRRC, 0x0000 }, { REG_ASRPM1, 0x0000 },
+       { REG_ASRPM2, 0x0000 }, { REG_ASRPM3, 0x0000 },
+       { REG_ASRPM4, 0x0000 }, { REG_ASRPM5, 0x0000 },
+       { REG_ASRTFR1, 0x0000 }, { REG_ASRCCR, 0x0000 },
+       { REG_ASRDIA, 0x0000 }, { REG_ASRDOA, 0x0000 },
+       { REG_ASRDIB, 0x0000 }, { REG_ASRDOB, 0x0000 },
+       { REG_ASRDIC, 0x0000 }, { REG_ASRDOC, 0x0000 },
+       { REG_ASRIDRHA, 0x0000 }, { REG_ASRIDRLA, 0x0000 },
+       { REG_ASRIDRHB, 0x0000 }, { REG_ASRIDRLB, 0x0000 },
+       { REG_ASRIDRHC, 0x0000 }, { REG_ASRIDRLC, 0x0000 },
+       { REG_ASR76K, 0x0A47 }, { REG_ASR56K, 0x0DF3 },
+       { REG_ASRMCRA, 0x0000 }, { REG_ASRFSTA, 0x0000 },
+       { REG_ASRMCRB, 0x0000 }, { REG_ASRFSTB, 0x0000 },
+       { REG_ASRMCRC, 0x0000 }, { REG_ASRFSTC, 0x0000 },
+       { REG_ASRMCR1A, 0x0000 }, { REG_ASRMCR1B, 0x0000 },
+       { REG_ASRMCR1C, 0x0000 },
+};
+
 static const struct regmap_config fsl_asrc_regmap_config = {
        .reg_bits = 32,
        .reg_stride = 4,
        .val_bits = 32,
 
        .max_register = REG_ASRMCR1C,
+       .reg_defaults = fsl_asrc_reg,
+       .num_reg_defaults = ARRAY_SIZE(fsl_asrc_reg),
        .readable_reg = fsl_asrc_readable_reg,
        .volatile_reg = fsl_asrc_volatile_reg,
        .writeable_reg = fsl_asrc_writeable_reg,
index f373e37f83050a246c2d35fbed008db7cdd0b5a5..c74ba37f862c121b1114edd84bded49ec7d72907 100644 (file)
@@ -154,8 +154,10 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
                        while (val) {
                                regmap_read(i2s->regmap, I2S_CLR, &val);
                                retry--;
-                               if (!retry)
+                               if (!retry) {
                                        dev_warn(i2s->dev, "fail to clear\n");
+                                       break;
+                               }
                        }
                }
        }
index 0acf5d0eed53a30979f66d466252b51f660f3d2e..72118a77dd5b70aa2a08fb51c32b5204063829f5 100644 (file)
@@ -110,6 +110,7 @@ static const struct of_device_id snow_of_match[] = {
        { .compatible = "google,snow-audio-max98095", },
        {},
 };
+MODULE_DEVICE_TABLE(of, snow_of_match);
 
 static struct platform_driver snow_driver = {
        .driver = {
index 66fddec9543d0ecc1bb414871d035bc244abc521..88e5df474ccf0ed089e23d9fe00f1268189886c9 100644 (file)
@@ -1711,8 +1711,7 @@ static const struct snd_soc_dai_ops fsi_dai_ops = {
 static struct snd_pcm_hardware fsi_pcm_hardware = {
        .info =         SNDRV_PCM_INFO_INTERLEAVED      |
                        SNDRV_PCM_INFO_MMAP             |
-                       SNDRV_PCM_INFO_MMAP_VALID       |
-                       SNDRV_PCM_INFO_PAUSE,
+                       SNDRV_PCM_INFO_MMAP_VALID,
        .buffer_bytes_max       = 64 * 1024,
        .period_bytes_min       = 32,
        .period_bytes_max       = 8192,
index 1922ec57d10a1fd29c174295adb6de5446e8d7a2..70042197f9e26eaf6f95f5f429435388b12976b4 100644 (file)
@@ -886,8 +886,7 @@ static int rsnd_dai_probe(struct platform_device *pdev,
 static struct snd_pcm_hardware rsnd_pcm_hardware = {
        .info =         SNDRV_PCM_INFO_INTERLEAVED      |
                        SNDRV_PCM_INFO_MMAP             |
-                       SNDRV_PCM_INFO_MMAP_VALID       |
-                       SNDRV_PCM_INFO_PAUSE,
+                       SNDRV_PCM_INFO_MMAP_VALID,
        .buffer_bytes_max       = 64 * 1024,
        .period_bytes_min       = 32,
        .period_bytes_max       = 8192,
index 4c8f8a23a0e9de132827fc041438fc1e07a4892c..b60ff56ebc0f56c2199a3473521fa657d9436713 100644 (file)
@@ -884,7 +884,7 @@ static struct snd_soc_dai *snd_soc_find_dai(
        list_for_each_entry(component, &component_list, list) {
                if (dlc->of_node && component->dev->of_node != dlc->of_node)
                        continue;
-               if (dlc->name && strcmp(dev_name(component->dev), dlc->name))
+               if (dlc->name && strcmp(component->name, dlc->name))
                        continue;
                list_for_each_entry(dai, &component->dai_list, list) {
                        if (dlc->dai_name && strcmp(dai->name, dlc->dai_name))
index 002311afdeaa8bd6ceb40d120b0c6afaa13c6119..57277dd79e112c2b59bf2ee3925bae6228bc30ac 100644 (file)
@@ -1522,13 +1522,36 @@ static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
                dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture);
 }
 
+static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
+
+/* Set FE's runtime_update state; the state is protected via PCM stream lock
+ * for avoiding the race with trigger callback.
+ * If the state is unset and a trigger is pending while the previous operation,
+ * process the pending trigger action here.
+ */
+static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
+                                    int stream, enum snd_soc_dpcm_update state)
+{
+       struct snd_pcm_substream *substream =
+               snd_soc_dpcm_get_substream(fe, stream);
+
+       snd_pcm_stream_lock_irq(substream);
+       if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
+               dpcm_fe_dai_do_trigger(substream,
+                                      fe->dpcm[stream].trigger_pending - 1);
+               fe->dpcm[stream].trigger_pending = 0;
+       }
+       fe->dpcm[stream].runtime_update = state;
+       snd_pcm_stream_unlock_irq(substream);
+}
+
 static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
 {
        struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
        struct snd_pcm_runtime *runtime = fe_substream->runtime;
        int stream = fe_substream->stream, ret = 0;
 
-       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+       dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
 
        ret = dpcm_be_dai_startup(fe, fe_substream->stream);
        if (ret < 0) {
@@ -1550,13 +1573,13 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
        dpcm_set_fe_runtime(fe_substream);
        snd_pcm_limit_hw_rates(runtime);
 
-       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+       dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
        return 0;
 
 unwind:
        dpcm_be_dai_startup_unwind(fe, fe_substream->stream);
 be_err:
-       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+       dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
        return ret;
 }
 
@@ -1603,7 +1626,7 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
        struct snd_soc_pcm_runtime *fe = substream->private_data;
        int stream = substream->stream;
 
-       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+       dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
 
        /* shutdown the BEs */
        dpcm_be_dai_shutdown(fe, substream->stream);
@@ -1617,7 +1640,7 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
        dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
 
        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
-       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+       dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
        return 0;
 }
 
@@ -1665,7 +1688,7 @@ static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
        int err, stream = substream->stream;
 
        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
-       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+       dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
 
        dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
 
@@ -1680,7 +1703,7 @@ static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
        err = dpcm_be_dai_hw_free(fe, stream);
 
        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
-       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+       dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
 
        mutex_unlock(&fe->card->mutex);
        return 0;
@@ -1773,7 +1796,7 @@ static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
        int ret, stream = substream->stream;
 
        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
-       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+       dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
 
        memcpy(&fe->dpcm[substream->stream].hw_params, params,
                        sizeof(struct snd_pcm_hw_params));
@@ -1796,7 +1819,7 @@ static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
                fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
 
 out:
-       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+       dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
        mutex_unlock(&fe->card->mutex);
        return ret;
 }
@@ -1910,7 +1933,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
 }
 EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
 
-static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
+static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        struct snd_soc_pcm_runtime *fe = substream->private_data;
        int stream = substream->stream, ret;
@@ -1984,6 +2007,23 @@ out:
        return ret;
 }
 
+static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_soc_pcm_runtime *fe = substream->private_data;
+       int stream = substream->stream;
+
+       /* if FE's runtime_update is already set, we're in race;
+        * process this trigger later at exit
+        */
+       if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
+               fe->dpcm[stream].trigger_pending = cmd + 1;
+               return 0; /* delayed, assuming it's successful */
+       }
+
+       /* we're alone, let's trigger */
+       return dpcm_fe_dai_do_trigger(substream, cmd);
+}
+
 int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
 {
        struct snd_soc_dpcm *dpcm;
@@ -2027,7 +2067,7 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
 
        dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
 
-       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+       dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
 
        /* there is no point preparing this FE if there are no BEs */
        if (list_empty(&fe->dpcm[stream].be_clients)) {
@@ -2054,7 +2094,7 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
 
 out:
-       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+       dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
        mutex_unlock(&fe->card->mutex);
 
        return ret;
@@ -2201,11 +2241,11 @@ static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream)
 {
        int ret;
 
-       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+       dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
        ret = dpcm_run_update_startup(fe, stream);
        if (ret < 0)
                dev_err(fe->dev, "ASoC: failed to startup some BEs\n");
-       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+       dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
 
        return ret;
 }
@@ -2214,11 +2254,11 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
 {
        int ret;
 
-       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+       dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
        ret = dpcm_run_update_shutdown(fe, stream);
        if (ret < 0)
                dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
-       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+       dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
 
        return ret;
 }
index 2e4a9dbc51faeca29529da8d231d779a10b92aed..6e354d3268585bfa38e2e35e4b1c6382ceb10067 100644 (file)
@@ -2033,10 +2033,11 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
        cval->res = 1;
        cval->initialized = 1;
 
-       if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR)
-               cval->control = UAC2_CX_CLOCK_SELECTOR;
-       else
+       if (state->mixer->protocol == UAC_VERSION_1)
                cval->control = 0;
+       else /* UAC_VERSION_2 */
+               cval->control = (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) ?
+                       UAC2_CX_CLOCK_SELECTOR : UAC2_SU_SELECTOR;
 
        namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL);
        if (!namelist) {
index 7c83bab69deef832690c98c7babb00ded92d5784..8c9bf4b7aaf0e003db413347efe1ca2ae09053fe 100644 (file)
@@ -593,10 +593,10 @@ static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol,
        if (mixer->chip->shutdown)
                ret = -ENODEV;
        else
-               ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
+               ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
                                  USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                                  0, wIndex,
-                                 &tmp, sizeof(tmp), 1000);
+                                 &tmp, sizeof(tmp));
        up_read(&mixer->chip->shutdown_rwsem);
 
        if (ret < 0) {
index d2aa45a8d89546b378fa05fc94750a35f6fe5c18..60dfe0d28771bbc244ae8b4e41b737d8281c6f04 100644 (file)
@@ -1146,6 +1146,20 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
        if ((le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) &&
            (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
                mdelay(20);
+
+       /* Marantz/Denon devices with USB DAC functionality need a delay
+        * after each class compliant request
+        */
+       if ((le16_to_cpu(dev->descriptor.idVendor) == 0x154e) &&
+           (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) {
+
+               switch (le16_to_cpu(dev->descriptor.idProduct)) {
+               case 0x3005: /* Marantz HD-DAC1 */
+               case 0x3006: /* Marantz SA-14S1 */
+                       mdelay(20);
+                       break;
+               }
+       }
 }
 
 /*
@@ -1179,12 +1193,12 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
        /* iFi Audio micro/nano iDSD */
        case USB_ID(0x20b1, 0x3008):
                if (fp->altsetting == 2)
-                       return SNDRV_PCM_FMTBIT_DSD_U32_LE;
+                       return SNDRV_PCM_FMTBIT_DSD_U32_BE;
                break;
        /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */
        case USB_ID(0x20b1, 0x2009):
                if (fp->altsetting == 3)
-                       return SNDRV_PCM_FMTBIT_DSD_U32_LE;
+                       return SNDRV_PCM_FMTBIT_DSD_U32_BE;
                break;
        default:
                break;
index 3aaca49de3257eed0bd905ac26112cacd49588dd..aacdb59f30dedcd780ee29e2903d928194a42a5c 100644 (file)
@@ -1933,7 +1933,7 @@ out:
 
 int kvm_vgic_create(struct kvm *kvm)
 {
-       int i, vcpu_lock_idx = -1, ret = 0;
+       int i, vcpu_lock_idx = -1, ret;
        struct kvm_vcpu *vcpu;
 
        mutex_lock(&kvm->lock);
@@ -1948,6 +1948,7 @@ int kvm_vgic_create(struct kvm *kvm)
         * vcpu->mutex.  By grabbing the vcpu->mutex of all VCPUs we ensure
         * that no other VCPUs are run while we create the vgic.
         */
+       ret = -EBUSY;
        kvm_for_each_vcpu(i, vcpu, kvm) {
                if (!mutex_trylock(&vcpu->mutex))
                        goto out_unlock;
@@ -1955,11 +1956,10 @@ int kvm_vgic_create(struct kvm *kvm)
        }
 
        kvm_for_each_vcpu(i, vcpu, kvm) {
-               if (vcpu->arch.has_run_once) {
-                       ret = -EBUSY;
+               if (vcpu->arch.has_run_once)
                        goto out_unlock;
-               }
        }
+       ret = 0;
 
        spin_lock_init(&kvm->arch.vgic.lock);
        kvm->arch.vgic.in_kernel = true;
index 25ffac9e947d9d3e2d554e6c351dfa51811c0354..3cee7b167052b58e07c147abb65985865e39e0f9 100644 (file)
@@ -107,10 +107,10 @@ EXPORT_SYMBOL_GPL(kvm_rebooting);
 
 static bool largepages_enabled = true;
 
-bool kvm_is_mmio_pfn(pfn_t pfn)
+bool kvm_is_reserved_pfn(pfn_t pfn)
 {
        if (pfn_valid(pfn))
-               return !is_zero_pfn(pfn) && PageReserved(pfn_to_page(pfn));
+               return PageReserved(pfn_to_page(pfn));
 
        return true;
 }
@@ -1321,7 +1321,7 @@ static pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async,
        else if ((vma->vm_flags & VM_PFNMAP)) {
                pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) +
                        vma->vm_pgoff;
-               BUG_ON(!kvm_is_mmio_pfn(pfn));
+               BUG_ON(!kvm_is_reserved_pfn(pfn));
        } else {
                if (async && vma_is_valid(vma, write_fault))
                        *async = true;
@@ -1427,7 +1427,7 @@ static struct page *kvm_pfn_to_page(pfn_t pfn)
        if (is_error_noslot_pfn(pfn))
                return KVM_ERR_PTR_BAD_PAGE;
 
-       if (kvm_is_mmio_pfn(pfn)) {
+       if (kvm_is_reserved_pfn(pfn)) {
                WARN_ON(1);
                return KVM_ERR_PTR_BAD_PAGE;
        }
@@ -1456,7 +1456,7 @@ EXPORT_SYMBOL_GPL(kvm_release_page_clean);
 
 void kvm_release_pfn_clean(pfn_t pfn)
 {
-       if (!is_error_noslot_pfn(pfn) && !kvm_is_mmio_pfn(pfn))
+       if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn))
                put_page(pfn_to_page(pfn));
 }
 EXPORT_SYMBOL_GPL(kvm_release_pfn_clean);
@@ -1477,7 +1477,7 @@ static void kvm_release_pfn_dirty(pfn_t pfn)
 
 void kvm_set_pfn_dirty(pfn_t pfn)
 {
-       if (!kvm_is_mmio_pfn(pfn)) {
+       if (!kvm_is_reserved_pfn(pfn)) {
                struct page *page = pfn_to_page(pfn);
                if (!PageReserved(page))
                        SetPageDirty(page);
@@ -1487,14 +1487,14 @@ EXPORT_SYMBOL_GPL(kvm_set_pfn_dirty);
 
 void kvm_set_pfn_accessed(pfn_t pfn)
 {
-       if (!kvm_is_mmio_pfn(pfn))
+       if (!kvm_is_reserved_pfn(pfn))
                mark_page_accessed(pfn_to_page(pfn));
 }
 EXPORT_SYMBOL_GPL(kvm_set_pfn_accessed);
 
 void kvm_get_pfn(pfn_t pfn)
 {
-       if (!kvm_is_mmio_pfn(pfn))
+       if (!kvm_is_reserved_pfn(pfn))
                get_page(pfn_to_page(pfn));
 }
 EXPORT_SYMBOL_GPL(kvm_get_pfn);