]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'drm-intel-next-fixes-2015-04-15' of git://anongit.freedesktop.org/drm...
authorDave Airlie <airlied@redhat.com>
Wed, 15 Apr 2015 22:34:51 +0000 (08:34 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 15 Apr 2015 22:34:51 +0000 (08:34 +1000)
Misc i915 fixes.

* tag 'drm-intel-next-fixes-2015-04-15' of git://anongit.freedesktop.org/drm-intel:
  drm/i915: Dont enable CS_PARSER_ERROR interrupts at all
  drm/i915: Move drm_framebuffer_unreference out of struct_mutex for takeover
  drm/i915: Allocate connector state together with the connectors
  drm/i915/chv: Remove DPIO force latency causing interpair skew issue
  drm/i915: Don't cancel DRRS worker synchronously for flush/invalidate
  drm/i915: Fix locking in DRRS flush/invalidate hooks

534 files changed:
Documentation/DocBook/media/v4l/subdev-formats.xml
Documentation/devicetree/bindings/arm/bcm/brcm,bcm11351-cpu-method.txt [moved from Documentation/devicetree/bindings/arm/bcm/brcm,bcm11351-cpu-method with 100% similarity]
Documentation/devicetree/bindings/arm/bcm/brcm,bcm11351.txt [moved from Documentation/devicetree/bindings/arm/bcm/bcm11351.txt with 100% similarity]
Documentation/devicetree/bindings/arm/bcm/brcm,bcm21664.txt [moved from Documentation/devicetree/bindings/arm/bcm/bcm21664.txt with 100% similarity]
Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt [moved from Documentation/devicetree/bindings/arm/bcm2835.txt with 100% similarity]
Documentation/devicetree/bindings/arm/bcm/brcm,bcm4708.txt [moved from Documentation/devicetree/bindings/arm/bcm4708.txt with 100% similarity]
Documentation/devicetree/bindings/arm/bcm/brcm,bcm63138.txt [moved from Documentation/devicetree/bindings/arm/bcm/bcm63138.txt with 100% similarity]
Documentation/devicetree/bindings/arm/bcm/brcm,brcmstb.txt [moved from Documentation/devicetree/bindings/arm/brcm-brcmstb.txt with 100% similarity]
Documentation/devicetree/bindings/arm/bcm/brcm,cygnus.txt [moved from Documentation/devicetree/bindings/arm/bcm/cygnus.txt with 100% similarity]
Documentation/devicetree/bindings/bus/brcm,bus-axi.txt [moved from Documentation/devicetree/bindings/bus/bcma.txt with 100% similarity]
Documentation/devicetree/bindings/clock/brcm,kona-ccu.txt [moved from Documentation/devicetree/bindings/clock/bcm-kona-clock.txt with 100% similarity]
Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt [moved from Documentation/devicetree/bindings/dma/bcm2835-dma.txt with 100% similarity]
Documentation/devicetree/bindings/drm/imx/ldb.txt
Documentation/devicetree/bindings/gpio/brcm,kona-gpio.txt [moved from Documentation/devicetree/bindings/gpio/gpio-bcm-kona.txt with 100% similarity]
Documentation/devicetree/bindings/i2c/brcm,kona-i2c.txt [moved from Documentation/devicetree/bindings/i2c/i2c-bcm-kona.txt with 100% similarity]
Documentation/devicetree/bindings/mfd/brcm,bcm59056.txt [moved from Documentation/devicetree/bindings/mfd/bcm590xx.txt with 100% similarity]
Documentation/devicetree/bindings/mips/brcm/brcm,bcm3384-intc.txt [moved from Documentation/devicetree/bindings/mips/brcm/bcm3384-intc.txt with 100% similarity]
Documentation/devicetree/bindings/mips/brcm/brcm,bmips.txt [moved from Documentation/devicetree/bindings/mips/brcm/bmips.txt with 100% similarity]
Documentation/devicetree/bindings/mips/brcm/brcm,cm-dsl.txt [moved from Documentation/devicetree/bindings/mips/brcm/cm-dsl.txt with 100% similarity]
Documentation/devicetree/bindings/misc/brcm,kona-smc.txt [moved from Documentation/devicetree/bindings/misc/smc.txt with 100% similarity]
Documentation/devicetree/bindings/mmc/brcm,kona-sdhci.txt [moved from Documentation/devicetree/bindings/mmc/kona-sdhci.txt with 100% similarity]
Documentation/devicetree/bindings/net/brcm,bcm7445-switch-v4.0.txt [moved from Documentation/devicetree/bindings/net/broadcom-sf2.txt with 100% similarity]
Documentation/devicetree/bindings/net/brcm,bcmgenet.txt [moved from Documentation/devicetree/bindings/net/broadcom-bcmgenet.txt with 100% similarity]
Documentation/devicetree/bindings/net/brcm,systemport.txt [moved from Documentation/devicetree/bindings/net/broadcom-systemport.txt with 100% similarity]
Documentation/devicetree/bindings/net/brcm,unimac-mdio.txt [moved from Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt with 100% similarity]
Documentation/devicetree/bindings/net/dsa/dsa.txt
Documentation/devicetree/bindings/panel/ampire,am800480r3tmqwa1h.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/auo,b101ean01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/innolux,at043tn24.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/innolux,zj070na-01p.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/ortustech,com43h4m85ulc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/samsung,ltn140at29-301.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/shelly,sca07010-bfn-lnn.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/brcm,kona-usb2-phy.txt [moved from Documentation/devicetree/bindings/phy/bcm-phy.txt with 100% similarity]
Documentation/devicetree/bindings/pwm/brcm,kona-pwm.txt [moved from Documentation/devicetree/bindings/pwm/bcm-kona-pwm.txt with 100% similarity]
Documentation/devicetree/bindings/reset/brcm,bcm21664-resetmgr.txt [moved from Documentation/devicetree/bindings/arm/bcm/kona-resetmgr.txt with 100% similarity]
Documentation/devicetree/bindings/serial/brcm,bcm6345-uart.txt [moved from Documentation/devicetree/bindings/serial/bcm63xx-uart.txt with 100% similarity]
Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.txt [moved from Documentation/devicetree/bindings/sound/bcm2835-i2s.txt with 100% similarity]
Documentation/devicetree/bindings/timer/brcm,kona-timer.txt [moved from Documentation/devicetree/bindings/arm/bcm/kona-timer.txt with 100% similarity]
Documentation/devicetree/bindings/unittest.txt
Documentation/devicetree/bindings/usb/brcm,bcm3384-usb.txt [moved from Documentation/devicetree/bindings/mips/brcm/usb.txt with 100% similarity]
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/devicetree/bindings/watchdog/brcm,kona-wdt.txt [moved from Documentation/devicetree/bindings/arm/bcm/kona-wdt.txt with 100% similarity]
Documentation/devicetree/of_unittest.txt [moved from Documentation/devicetree/of_selftest.txt with 90% similarity]
Documentation/input/alps.txt
Documentation/input/event-codes.txt
Documentation/input/multi-touch-protocol.txt
MAINTAINERS
Makefile
arch/powerpc/include/asm/cputhreads.h
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/entry_64.S
arch/x86/kernel/kgdb.c
arch/x86/kernel/reboot.c
arch/x86/xen/p2m.c
block/blk-settings.c
drivers/ata/libata-core.c
drivers/coresight/of_coresight.c
drivers/dma/bcm2835-dma.c
drivers/dma/dma-jz4740.c
drivers/dma/edma.c
drivers/dma/moxart-dma.c
drivers/dma/omap-dma.c
drivers/firmware/dmi_scan.c
drivers/gpio/gpio-mpc8xxx.c
drivers/gpio/gpio-syscon.c
drivers/gpio/gpiolib-acpi.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
drivers/gpu/drm/amd/amdkfd/kfd_device.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
drivers/gpu/drm/amd/amdkfd/kfd_module.c
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
drivers/gpu/drm/amd/amdkfd/kfd_priv.h
drivers/gpu/drm/amd/amdkfd/kfd_process.c
drivers/gpu/drm/amd/amdkfd/kfd_topology.c
drivers/gpu/drm/amd/include/kgd_kfd_interface.h
drivers/gpu/drm/armada/armada_output.h
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
drivers/gpu/drm/bochs/bochs_hw.c
drivers/gpu/drm/bridge/Kconfig
drivers/gpu/drm/bridge/Makefile
drivers/gpu/drm/bridge/dw_hdmi.c
drivers/gpu/drm/bridge/ps8622.c [new file with mode: 0644]
drivers/gpu/drm/bridge/ptn3460.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_bridge.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_dp_helper.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_edid_load.c
drivers/gpu/drm/drm_fb_cma_helper.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_info.c
drivers/gpu/drm/drm_ioc32.c
drivers/gpu/drm/drm_ioctl.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_of.c
drivers/gpu/drm/drm_pci.c
drivers/gpu/drm/drm_plane_helper.c
drivers/gpu/drm/drm_probe_helper.c
drivers/gpu/drm/drm_vm.c
drivers/gpu/drm/exynos/exynos7_drm_decon.c
drivers/gpu/drm/exynos/exynos_dp_core.c
drivers/gpu/drm/exynos/exynos_drm_crtc.c
drivers/gpu/drm/exynos/exynos_drm_crtc.h
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_fb.c
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_fimd.h [new file with mode: 0644]
drivers/gpu/drm/exynos/exynos_drm_ipp.c
drivers/gpu/drm/exynos/exynos_drm_plane.c
drivers/gpu/drm/exynos/exynos_drm_plane.h
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/exynos/regs-mixer.h
drivers/gpu/drm/gma500/cdv_intel_display.c
drivers/gpu/drm/gma500/cdv_intel_hdmi.c
drivers/gpu/drm/gma500/cdv_intel_lvds.c
drivers/gpu/drm/gma500/gma_display.c
drivers/gpu/drm/gma500/mdfld_dsi_output.c
drivers/gpu/drm/gma500/mdfld_intel_display.c
drivers/gpu/drm/gma500/oaktrail_crtc.c
drivers/gpu/drm/gma500/oaktrail_hdmi.c
drivers/gpu/drm/gma500/psb_intel_display.c
drivers/gpu/drm/gma500/psb_intel_lvds.c
drivers/gpu/drm/i2c/adv7511.c
drivers/gpu/drm/i915/intel_sprite.c
drivers/gpu/drm/imx/Kconfig
drivers/gpu/drm/imx/dw_hdmi-imx.c
drivers/gpu/drm/imx/imx-drm-core.c
drivers/gpu/drm/imx/imx-drm.h
drivers/gpu/drm/imx/imx-ldb.c
drivers/gpu/drm/imx/imx-tve.c
drivers/gpu/drm/imx/ipuv3-crtc.c
drivers/gpu/drm/imx/ipuv3-plane.c
drivers/gpu/drm/imx/ipuv3-plane.h
drivers/gpu/drm/imx/parallel-display.c
drivers/gpu/drm/mgag200/mgag200_mode.c
drivers/gpu/drm/msm/Kconfig
drivers/gpu/drm/msm/Makefile
drivers/gpu/drm/msm/dsi/dsi.c [new file with mode: 0644]
drivers/gpu/drm/msm/dsi/dsi.h [new file with mode: 0644]
drivers/gpu/drm/msm/dsi/dsi.xml.h
drivers/gpu/drm/msm/dsi/dsi_host.c [new file with mode: 0644]
drivers/gpu/drm/msm/dsi/dsi_manager.c [new file with mode: 0644]
drivers/gpu/drm/msm/dsi/dsi_phy.c [new file with mode: 0644]
drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h
drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h
drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h
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/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
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_kms.h
drivers/gpu/drm/nouveau/dispnv04/crtc.c
drivers/gpu/drm/nouveau/dispnv04/dac.c
drivers/gpu/drm/nouveau/dispnv04/dfp.c
drivers/gpu/drm/nouveau/dispnv04/disp.c
drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
drivers/gpu/drm/nouveau/include/nvif/class.h
drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h
drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h
drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_chan.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drm.h
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_ttm.c
drivers/gpu/drm/nouveau/nv84_fence.c
drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c
drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm206.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/macros.fuc
drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c
drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c
drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h
drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h
drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk20a.c [deleted file]
drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c
drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c
drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h
drivers/gpu/drm/omapdrm/omap_connector.c
drivers/gpu/drm/omapdrm/omap_crtc.c
drivers/gpu/drm/omapdrm/omap_dmm_priv.h
drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
drivers/gpu/drm/omapdrm/omap_dmm_tiler.h
drivers/gpu/drm/omapdrm/omap_drv.c
drivers/gpu/drm/omapdrm/omap_drv.h
drivers/gpu/drm/omapdrm/omap_fb.c
drivers/gpu/drm/omapdrm/omap_fbdev.c
drivers/gpu/drm/omapdrm/omap_gem.c
drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
drivers/gpu/drm/omapdrm/omap_irq.c
drivers/gpu/drm/omapdrm/omap_plane.c
drivers/gpu/drm/panel/Kconfig
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/qxl/qxl_drv.c
drivers/gpu/drm/radeon/Kconfig
drivers/gpu/drm/radeon/Makefile
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/btc_dpm.c
drivers/gpu/drm/radeon/ci_dpm.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cikd.h
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/kv_dpm.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/ni_dpm.c
drivers/gpu/drm/radeon/ni_reg.h
drivers/gpu/drm/radeon/nid.h
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_audio.c
drivers/gpu/drm/radeon/radeon_bios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_dp_auxch.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_dp_mst.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/radeon/radeon_kfd.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_legacy_encoders.c
drivers/gpu/drm/radeon/radeon_mn.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_ring.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/radeon_vce.c
drivers/gpu/drm/radeon/rs780_dpm.c
drivers/gpu/drm/radeon/rv6xx_dpm.c
drivers/gpu/drm/radeon/rv770_dpm.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/radeon/sid.h
drivers/gpu/drm/radeon/sumo_dpm.c
drivers/gpu/drm/radeon/trinity_dpm.c
drivers/gpu/drm/radeon/vce_v2_0.c
drivers/gpu/drm/rcar-du/rcar_du_crtc.c
drivers/gpu/drm/rcar-du/rcar_du_drv.c
drivers/gpu/drm/rcar-du/rcar_du_kms.c
drivers/gpu/drm/rcar-du/rcar_du_plane.c
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
drivers/gpu/drm/rockchip/rockchip_drm_gem.c
drivers/gpu/drm/rockchip/rockchip_drm_gem.h
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/sti/sti_drm_crtc.c
drivers/gpu/drm/sti/sti_drm_drv.c
drivers/gpu/drm/sti/sti_drm_drv.h
drivers/gpu/drm/sti/sti_drm_plane.c
drivers/gpu/drm/sti/sti_dvo.c
drivers/gpu/drm/sti/sti_hda.c
drivers/gpu/drm/sti/sti_hdmi.c
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/dc.h
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/drm.h
drivers/gpu/drm/tegra/hdmi.c
drivers/gpu/drm/tegra/hdmi.h
drivers/gpu/drm/tegra/sor.c
drivers/gpu/drm/vgem/Makefile [new file with mode: 0644]
drivers/gpu/drm/vgem/vgem_dma_buf.c [new file with mode: 0644]
drivers/gpu/drm/vgem/vgem_drv.c [new file with mode: 0644]
drivers/gpu/drm/vgem/vgem_drv.h [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/host1x/syncpt.c
drivers/gpu/ipu-v3/ipu-dc.c
drivers/gpu/ipu-v3/ipu-di.c
drivers/gpu/ipu-v3/ipu-ic.c
drivers/iio/accel/bma180.c
drivers/iio/accel/bmc150-accel.c
drivers/iio/accel/kxcjk-1013.c
drivers/iio/adc/Kconfig
drivers/iio/adc/at91_adc.c
drivers/iio/adc/ti_am335x_adc.c
drivers/iio/adc/vf610_adc.c
drivers/iio/gyro/bmg160.c
drivers/iio/imu/adis_trigger.c
drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
drivers/iio/imu/kmx61.c
drivers/iio/industrialio-core.c
drivers/iio/industrialio-event.c
drivers/iio/proximity/sx9500.c
drivers/infiniband/core/umem.c
drivers/input/mouse/alps.c
drivers/input/mouse/synaptics.c
drivers/iommu/arm-smmu.c
drivers/iommu/intel-iommu.c
drivers/iommu/ipmmu-vmsa.c
drivers/irqchip/irq-gic-v3-its.c
drivers/lguest/Kconfig
drivers/media/platform/am437x/am437x-vpfe.c
drivers/media/platform/soc_camera/soc_camera.c
drivers/net/bonding/bond_main.c
drivers/net/can/flexcan.c
drivers/net/can/usb/gs_usb.c
drivers/net/can/usb/kvaser_usb.c
drivers/net/can/usb/peak_usb/pcan_ucan.h
drivers/net/can/usb/peak_usb/pcan_usb_fd.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/sge.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h
drivers/net/ethernet/chelsio/cxgb4vf/sge.c
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/ucc_geth.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/mellanox/mlx4/cmd.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/eq.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/rocker/rocker.c
drivers/net/ipvlan/ipvlan.h
drivers/net/ipvlan/ipvlan_core.c
drivers/net/ipvlan/ipvlan_main.c
drivers/net/usb/asix_common.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/r8152.c
drivers/net/usb/sr9800.c
drivers/net/usb/usbnet.c
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/common.h
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/brcm80211/brcmfmac/feature.c
drivers/net/wireless/iwlwifi/dvm/dev.h
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/dvm/ucode.c
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/time-event.c
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/xen-netfront.c
drivers/of/Makefile
drivers/of/address.c
drivers/of/base.c
drivers/of/unittest-data/.gitignore [new file with mode: 0644]
drivers/of/unittest-data/Makefile [new file with mode: 0644]
drivers/of/unittest-data/tests-overlay.dtsi
drivers/of/unittest.c
drivers/staging/iio/Kconfig
drivers/staging/iio/magnetometer/hmc5843_core.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/samsung.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-pci.c
drivers/usb/isp1760/isp1760-udc.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/keyspan_pda.c
drivers/video/fbdev/omap2/dss/omapdss-boot-init.c
drivers/xen/Kconfig
drivers/xen/balloon.c
fs/cifs/cifsencrypt.c
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/fs-writeback.c
fs/locks.c
fs/nfsd/blocklayout.c
fs/nfsd/blocklayoutxdr.c
fs/nfsd/nfs4layouts.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfscache.c
include/drm/bridge/dw_hdmi.h
include/drm/drmP.h
include/drm/drm_atomic.h
include/drm/drm_atomic_helper.h
include/drm/drm_crtc.h
include/drm/drm_crtc_helper.h
include/drm/drm_dp_helper.h
include/drm/drm_dp_mst_helper.h
include/drm/drm_edid.h
include/drm/drm_fb_helper.h
include/drm/drm_gem.h
include/drm/drm_panel.h
include/drm/drm_plane_helper.h
include/linux/fs.h
include/linux/host1x.h
include/linux/irqchip/arm-gic-v3.h
include/linux/lcm.h
include/linux/netdevice.h
include/linux/of_graph.h
include/linux/sunrpc/debug.h
include/linux/usb/usbnet.h
include/linux/writeback.h
include/net/ip.h
include/net/ip6_route.h
include/net/sock.h
include/uapi/drm/nouveau_drm.h
include/uapi/drm/radeon_drm.h
include/uapi/drm/tegra_drm.h
include/uapi/linux/input.h
include/uapi/linux/media-bus-format.h
include/uapi/linux/nfsd/export.h
include/video/imx-ipu-v3.h
include/video/samsung_fimd.h
kernel/sysctl.c
lib/lcm.c
lib/nlattr.c
net/core/dev.c
net/core/fib_rules.c
net/core/net_namespace.c
net/core/rtnetlink.c
net/core/sock.c
net/decnet/dn_rules.c
net/dsa/dsa.c
net/ipv4/fib_frontend.c
net/ipv4/ipmr.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv6/fib6_rules.c
net/ipv6/ip6_output.c
net/ipv6/ip6mr.c
net/ipv6/ndisc.c
net/ipv6/tcp_ipv6.c
net/iucv/af_iucv.c
net/l2tp/l2tp_core.c
net/mac80211/agg-rx.c
net/mac80211/rx.c
net/mac80211/sta_info.h
net/openvswitch/vport.c
net/sunrpc/clnt.c
net/sunrpc/debugfs.c
net/sunrpc/sunrpc_syms.c
net/sunrpc/xprt.c
net/tipc/core.c

index c5ea868e390958d499681d1b63570c11c9933721..18b71aff48c90e247beea4300a4b34ca46ffc12c 100644 (file)
@@ -91,7 +91,9 @@ see <xref linkend="colorspaces" />.</entry>
        <listitem><para>For formats where the total number of bits per pixel is smaller
        than the number of bus samples per pixel times the bus width, a padding
        value stating if the bytes are padded in their most high order bits
-       (PADHI) or low order bits (PADLO).</para></listitem>
+       (PADHI) or low order bits (PADLO). A "C" prefix is used for component-wise
+       padding in the most high order bits (CPADHI) or low order bits (CPADLO)
+       of each separate component.</para></listitem>
        <listitem><para>For formats where the number of bus samples per pixel is larger
        than 1, an endianness value stating if the pixel is transferred MSB first
        (BE) or LSB first (LE).</para></listitem>
@@ -192,6 +194,24 @@ see <xref linkend="colorspaces" />.</entry>
            </row>
          </thead>
          <tbody valign="top">
+           <row id="MEDIA-BUS-FMT-RGB444-1X12">
+             <entry>MEDIA_BUS_FMT_RGB444_1X12</entry>
+             <entry>0x100e</entry>
+             <entry></entry>
+             &dash-ent-20;
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
            <row id="MEDIA-BUS-FMT-RGB444-2X8-PADHI-BE">
              <entry>MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE</entry>
              <entry>0x1001</entry>
@@ -304,6 +324,28 @@ see <xref linkend="colorspaces" />.</entry>
              <entry>g<subscript>4</subscript></entry>
              <entry>g<subscript>3</subscript></entry>
            </row>
+           <row id="MEDIA-BUS-FMT-RGB565-1X16">
+             <entry>MEDIA_BUS_FMT_RGB565_1X16</entry>
+             <entry>0x100f</entry>
+             <entry></entry>
+             &dash-ent-16;
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
            <row id="MEDIA-BUS-FMT-BGR565-2X8-BE">
              <entry>MEDIA_BUS_FMT_BGR565_2X8_BE</entry>
              <entry>0x1005</entry>
@@ -440,6 +482,96 @@ see <xref linkend="colorspaces" />.</entry>
              <entry>b<subscript>1</subscript></entry>
              <entry>b<subscript>0</subscript></entry>
            </row>
+           <row id="MEDIA-BUS-FMT-RGB666-1X24_CPADHI">
+             <entry>MEDIA_BUS_FMT_RGB666_1X24_CPADHI</entry>
+             <entry>0x1015</entry>
+             <entry></entry>
+             &dash-ent-8;
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>r<subscript>5</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row id="MEDIA-BUS-FMT-BGR888-1X24">
+             <entry>MEDIA_BUS_FMT_BGR888_1X24</entry>
+             <entry>0x1013</entry>
+             <entry></entry>
+             &dash-ent-8;
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>r<subscript>7</subscript></entry>
+             <entry>r<subscript>6</subscript></entry>
+             <entry>r<subscript>5</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+           <row id="MEDIA-BUS-FMT-GBR888-1X24">
+             <entry>MEDIA_BUS_FMT_GBR888_1X24</entry>
+             <entry>0x1014</entry>
+             <entry></entry>
+             &dash-ent-8;
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+             <entry>r<subscript>7</subscript></entry>
+             <entry>r<subscript>6</subscript></entry>
+             <entry>r<subscript>5</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
            <row id="MEDIA-BUS-FMT-RGB888-1X24">
              <entry>MEDIA_BUS_FMT_RGB888_1X24</entry>
              <entry>0x100a</entry>
@@ -582,6 +714,261 @@ see <xref linkend="colorspaces" />.</entry>
          </tbody>
        </tgroup>
       </table>
+
+      <para>On LVDS buses, usually each sample is transferred serialized in
+      seven time slots per pixel clock, on three (18-bit) or four (24-bit)
+      differential data pairs at the same time. The remaining bits are used for
+      control signals as defined by SPWG/PSWG/VESA or JEIDA standards.
+      The 24-bit RGB format serialized in seven time slots on four lanes using
+      JEIDA defined bit mapping will be named
+      <constant>MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA</constant>, for example.
+      </para>
+
+      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-rgb-lvds">
+       <title>LVDS RGB formats</title>
+       <tgroup cols="8">
+         <colspec colname="id" align="left" />
+         <colspec colname="code" align="center" />
+         <colspec colname="slot" align="center" />
+         <colspec colname="lane" />
+         <colspec colnum="5" colname="l03" align="center" />
+         <colspec colnum="6" colname="l02" align="center" />
+         <colspec colnum="7" colname="l01" align="center" />
+         <colspec colnum="8" colname="l00" align="center" />
+         <spanspec namest="l03" nameend="l00" spanname="l0" />
+         <thead>
+           <row>
+             <entry>Identifier</entry>
+             <entry>Code</entry>
+             <entry></entry>
+             <entry></entry>
+             <entry spanname="l0">Data organization</entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>Timeslot</entry>
+             <entry>Lane</entry>
+             <entry>3</entry>
+             <entry>2</entry>
+             <entry>1</entry>
+             <entry>0</entry>
+           </row>
+         </thead>
+         <tbody valign="top">
+           <row id="MEDIA-BUS-FMT-RGB666-1X7X3-SPWG">
+             <entry>MEDIA_BUS_FMT_RGB666_1X7X3_SPWG</entry>
+             <entry>0x1010</entry>
+             <entry>0</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>d</entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>1</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>d</entry>
+             <entry>b<subscript>0</subscript></entry>
+             <entry>r<subscript>5</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>2</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>d</entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>3</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>4</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>5</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>6</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+           <row id="MEDIA-BUS-FMT-RGB888-1X7X4-SPWG">
+             <entry>MEDIA_BUS_FMT_RGB888_1X7X4_SPWG</entry>
+             <entry>0x1011</entry>
+             <entry>0</entry>
+             <entry></entry>
+             <entry>d</entry>
+             <entry>d</entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>1</entry>
+             <entry></entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>d</entry>
+             <entry>b<subscript>0</subscript></entry>
+             <entry>r<subscript>5</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>2</entry>
+             <entry></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>d</entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>3</entry>
+             <entry></entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>4</entry>
+             <entry></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>5</entry>
+             <entry></entry>
+             <entry>r<subscript>7</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>6</entry>
+             <entry></entry>
+             <entry>r<subscript>6</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+           <row id="MEDIA-BUS-FMT-RGB888-1X7X4-JEIDA">
+             <entry>MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA</entry>
+             <entry>0x1012</entry>
+             <entry>0</entry>
+             <entry></entry>
+             <entry>d</entry>
+             <entry>d</entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>1</entry>
+             <entry></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>d</entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>r<subscript>7</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>2</entry>
+             <entry></entry>
+             <entry>b<subscript>0</subscript></entry>
+             <entry>d</entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>r<subscript>6</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>3</entry>
+             <entry></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>r<subscript>5</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>4</entry>
+             <entry></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>5</entry>
+             <entry></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>6</entry>
+             <entry></entry>
+             <entry>r<subscript>0</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
     </section>
 
     <section>
@@ -2660,6 +3047,43 @@ see <xref linkend="colorspaces" />.</entry>
              <entry>u<subscript>1</subscript></entry>
              <entry>u<subscript>0</subscript></entry>
            </row>
+           <row id="MEDIA-BUS-FMT-YUV8-1X24">
+             <entry>MEDIA_BUS_FMT_YUV8_1X24</entry>
+             <entry>0x2024</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
            <row id="MEDIA-BUS-FMT-YUV10-1X30">
              <entry>MEDIA_BUS_FMT_YUV10_1X30</entry>
              <entry>0x2016</entry>
index 443bcb6134d53ca6afc8587b611a82ec30e89d22..9a21366436f6de14f862bed9ee71bb054e7b03d4 100644 (file)
@@ -44,23 +44,30 @@ Optional properties:
 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.
+Each LVDS Channel has to contain either an of graph link to a panel device node
+or a display-timings node that describes the video timings for the connected
+LVDS display as well as the fsl,data-mapping and fsl,data-width properties.
 
 Required properties:
  - reg : should be <0> or <1>
+ - port: Input and output port nodes with endpoint definitions as defined in
+   Documentation/devicetree/bindings/graph.txt.
+   On i.MX5, the internal two-input-multiplexer is used. Due to hardware
+   limitations, only one input port (port@[0,1]) can be used for each channel
+   (lvds-channel@[0,1], respectively).
+   On i.MX6, there should be four input ports (port@[0-3]) that correspond
+   to the four LVDS multiplexer inputs.
+   A single output port (port@2 on i.MX5, port@4 on i.MX6) must be connected
+   to a panel input port. Optionally, the output port can be left out if
+   display-timings are used instead.
+
+Optional properties (required if display-timings are used):
+ - display-timings : A node that describes the display timings as defined in
+   Documentation/devicetree/bindings/video/display-timing.txt.
  - 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:
 
@@ -73,23 +80,21 @@ ldb: ldb@53fa8008 {
        #size-cells = <0>;
        compatible = "fsl,imx53-ldb";
        gpr = <&gpr>;
-       clocks = <&clks 122>, <&clks 120>,
-                <&clks 115>, <&clks 116>,
-                <&clks 123>, <&clks 85>;
+       clocks = <&clks IMX5_CLK_LDB_DI0_SEL>,
+                <&clks IMX5_CLK_LDB_DI1_SEL>,
+                <&clks IMX5_CLK_IPU_DI0_SEL>,
+                <&clks IMX5_CLK_IPU_DI1_SEL>,
+                <&clks IMX5_CLK_LDB_DI0_GATE>,
+                <&clks IMX5_CLK_LDB_DI1_GATE>;
        clock-names = "di0_pll", "di1_pll",
                      "di0_sel", "di1_sel",
                      "di0", "di1";
 
+       /* Using an of-graph endpoint link to connect the panel */
        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>;
@@ -98,8 +103,17 @@ ldb: ldb@53fa8008 {
                                remote-endpoint = <&ipu_di0_lvds0>;
                        };
                };
+
+               port@2 {
+                       reg = <2>;
+
+                       lvds0_out: endpoint {
+                               remote-endpoint = <&panel_in>;
+                       };
+               };
        };
 
+       /* Using display-timings and fsl,data-mapping/width instead */
        lvds-channel@1 {
                #address-cells = <1>;
                #size-cells = <0>;
@@ -120,3 +134,13 @@ ldb: ldb@53fa8008 {
                };
        };
 };
+
+panel: lvds-panel {
+       /* ... */
+
+       port {
+               panel_in: endpoint {
+                       remote-endpoint = <&lvds0_out>;
+               };
+       };
+};
index e124847443f87c9465ec82dc03ce792d2d1cf5c4..f0b4cd72411d66bf12aeec3d64335d6641b26674 100644 (file)
@@ -19,7 +19,9 @@ the parent DSA node. The maximum number of allowed child nodes is 4
 (DSA_MAX_SWITCHES).
 Each of these switch child nodes should have the following required properties:
 
-- reg                  : Describes the switch address on the MII bus
+- reg                  : Contains two fields. The first one describes the
+                         address on the MII bus. The second is the switch
+                         number that must be unique in cascaded configurations
 - #address-cells       : Must be 1
 - #size-cells          : Must be 0
 
diff --git a/Documentation/devicetree/bindings/panel/ampire,am800480r3tmqwa1h.txt b/Documentation/devicetree/bindings/panel/ampire,am800480r3tmqwa1h.txt
new file mode 100644 (file)
index 0000000..83e2cae
--- /dev/null
@@ -0,0 +1,7 @@
+Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "ampire,am800480r3tmqwa1h"
+
+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/auo,b101ean01.txt b/Documentation/devicetree/bindings/panel/auo,b101ean01.txt
new file mode 100644 (file)
index 0000000..3590b07
--- /dev/null
@@ -0,0 +1,7 @@
+AU Optronics Corporation 10.1" WSVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "auo,b101ean01"
+
+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,at043tn24.txt b/Documentation/devicetree/bindings/panel/innolux,at043tn24.txt
new file mode 100644 (file)
index 0000000..4104226
--- /dev/null
@@ -0,0 +1,7 @@
+Innolux AT043TN24 4.3" WQVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "innolux,at043tn24"
+
+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,zj070na-01p.txt b/Documentation/devicetree/bindings/panel/innolux,zj070na-01p.txt
new file mode 100644 (file)
index 0000000..824f87f
--- /dev/null
@@ -0,0 +1,7 @@
+Innolux Corporation 7.0" WSVGA (1024x600) TFT LCD panel
+
+Required properties:
+- compatible: should be "innolux,zj070na-01p"
+
+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/ortustech,com43h4m85ulc.txt b/Documentation/devicetree/bindings/panel/ortustech,com43h4m85ulc.txt
new file mode 100644 (file)
index 0000000..de19e93
--- /dev/null
@@ -0,0 +1,7 @@
+OrtusTech COM43H4M85ULC Blanview 3.7" TFT-LCD panel
+
+Required properties:
+- compatible: should be "ortustech,com43h4m85ulc"
+
+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/samsung,ltn140at29-301.txt b/Documentation/devicetree/bindings/panel/samsung,ltn140at29-301.txt
new file mode 100644 (file)
index 0000000..e7f969d
--- /dev/null
@@ -0,0 +1,7 @@
+Samsung Electronics 14" WXGA (1366x768) TFT LCD panel
+
+Required properties:
+- compatible: should be "samsung,ltn140at29-301"
+
+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/shelly,sca07010-bfn-lnn.txt b/Documentation/devicetree/bindings/panel/shelly,sca07010-bfn-lnn.txt
new file mode 100644 (file)
index 0000000..fc1ea9e
--- /dev/null
@@ -0,0 +1,7 @@
+Shelly SCA07010-BFN-LNN 7.0" WVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "shelly,sca07010-bfn-lnn"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
index 8933211f32f945c70b568d35372342ab3baca3d3..3bf58c20fe94da71ecae272e7d86256bd42f0683 100644 (file)
@@ -1,60 +1,60 @@
-1) OF selftest platform device
+1) OF unittest platform device
 
-** selftest
+** unittest
 
 Required properties:
-- compatible: must be "selftest"
+- compatible: must be "unittest"
 
 All other properties are optional.
 
 Example:
-       selftest {
-               compatible = "selftest";
+       unittest {
+               compatible = "unittest";
                status = "okay";
        };
 
-2) OF selftest i2c adapter platform device
+2) OF unittest i2c adapter platform device
 
 ** platform device unittest adapter
 
 Required properties:
-- compatible: must be selftest-i2c-bus
+- compatible: must be unittest-i2c-bus
 
-Children nodes contain selftest i2c devices.
+Children nodes contain unittest i2c devices.
 
 Example:
-       selftest-i2c-bus {
-               compatible = "selftest-i2c-bus";
+       unittest-i2c-bus {
+               compatible = "unittest-i2c-bus";
                status = "okay";
        };
 
-3) OF selftest i2c device
+3) OF unittest i2c device
 
-** I2C selftest device
+** I2C unittest device
 
 Required properties:
-- compatible: must be selftest-i2c-dev
+- compatible: must be unittest-i2c-dev
 
 All other properties are optional
 
 Example:
-       selftest-i2c-dev {
-               compatible = "selftest-i2c-dev";
+       unittest-i2c-dev {
+               compatible = "unittest-i2c-dev";
                status = "okay";
        };
 
-4) OF selftest i2c mux device
+4) OF unittest i2c mux device
 
-** I2C selftest mux
+** I2C unittest mux
 
 Required properties:
-- compatible: must be selftest-i2c-mux
+- compatible: must be unittest-i2c-mux
 
-Children nodes contain selftest i2c bus nodes per channel.
+Children nodes contain unittest i2c bus nodes per channel.
 
 Example:
-       selftest-i2c-mux {
-               compatible = "selftest-i2c-mux";
+       unittest-i2c-mux {
+               compatible = "unittest-i2c-mux";
                status = "okay";
                #address-cells = <1>;
                #size-cells = <0>;
@@ -64,7 +64,7 @@ Example:
                        #size-cells = <0>;
                        i2c-dev {
                                reg = <8>;
-                               compatible = "selftest-i2c-dev";
+                               compatible = "unittest-i2c-dev";
                                status = "okay";
                        };
                };
index fae26d014aaf25c83f499889969e1cb017491f34..772b24f8638814a7398abdcb374eb11a04c4a237 100644 (file)
@@ -17,6 +17,7 @@ altr  Altera Corp.
 amcc   Applied Micro Circuits Corporation (APM, formally AMCC)
 amd    Advanced Micro Devices (AMD), Inc.
 amlogic        Amlogic, Inc.
+ampire Ampire Co., Ltd.
 ams    AMS AG
 amstaos        AMS-Taos Inc.
 apm    Applied Micro Circuits Corporation (APM)
@@ -132,6 +133,7 @@ nvidia      NVIDIA
 nxp    NXP Semiconductors
 onnn   ON Semiconductor Corp.
 opencores      OpenCores.org
+ortustech      Ortus Technology Co., Ltd.
 ovti   OmniVision Technologies
 panasonic      Panasonic Corporation
 parade Parade Technologies Inc.
similarity index 90%
rename from Documentation/devicetree/of_selftest.txt
rename to Documentation/devicetree/of_unittest.txt
index 57a808b588bffb40162f4f4061fd323727ef5342..3e4e7d48ae93142bd5a1769ec3a9b4f2ffb0a926 100644 (file)
@@ -1,11 +1,11 @@
-Open Firmware Device Tree Selftest
+Open Firmware Device Tree Unittest
 ----------------------------------
 
 Author: Gaurav Minocha <gaurav.minocha.os@gmail.com>
 
 1. Introduction
 
-This document explains how the test data required for executing OF selftest
+This document explains how the test data required for executing OF unittest
 is attached to the live tree dynamically, independent of the machine's
 architecture.
 
@@ -22,31 +22,31 @@ most of the device drivers in various use cases.
 
 2. Test-data
 
-The Device Tree Source file (drivers/of/testcase-data/testcases.dts) contains
+The Device Tree Source file (drivers/of/unittest-data/testcases.dts) contains
 the test data required for executing the unit tests automated in
-drivers/of/selftests.c. Currently, following Device Tree Source Include files
-(.dtsi) are included in testcase.dts:
+drivers/of/unittest.c. Currently, following Device Tree Source Include files
+(.dtsi) are included in testcases.dts:
 
-drivers/of/testcase-data/tests-interrupts.dtsi
-drivers/of/testcase-data/tests-platform.dtsi
-drivers/of/testcase-data/tests-phandle.dtsi
-drivers/of/testcase-data/tests-match.dtsi
+drivers/of/unittest-data/tests-interrupts.dtsi
+drivers/of/unittest-data/tests-platform.dtsi
+drivers/of/unittest-data/tests-phandle.dtsi
+drivers/of/unittest-data/tests-match.dtsi
 
 When the kernel is build with OF_SELFTEST enabled, then the following make rule
 
 $(obj)/%.dtb: $(src)/%.dts FORCE
        $(call if_changed_dep, dtc)
 
-is used to compile the DT source file (testcase.dts) into a binary blob
-(testcase.dtb), also referred as flattened DT.
+is used to compile the DT source file (testcases.dts) into a binary blob
+(testcases.dtb), also referred as flattened DT.
 
 After that, using the following rule the binary blob above is wrapped as an
-assembly file (testcase.dtb.S).
+assembly file (testcases.dtb.S).
 
 $(obj)/%.dtb.S: $(obj)/%.dtb
        $(call cmd, dt_S_dtb)
 
-The assembly file is compiled into an object file (testcase.dtb.o), and is
+The assembly file is compiled into an object file (testcases.dtb.o), and is
 linked into the kernel image.
 
 
@@ -98,7 +98,7 @@ child11 -> sibling12 -> sibling13 -> sibling14 -> null
 Figure 1: Generic structure of un-flattened device tree
 
 
-Before executing OF selftest, it is required to attach the test data to
+Before executing OF unittest, it is required to attach the test data to
 machine's device tree (if present). So, when selftest_data_add() is called,
 at first it reads the flattened device tree data linked into the kernel image
 via the following kernel symbols:
index a63e5e013a8cddee63b1d3520dd1c2c73e80dc31..92ae734c00c348ab810373e0dc838a92462c932f 100644 (file)
@@ -114,6 +114,9 @@ ALPS Absolute Mode - Protocol Version 2
  byte 4:  0   y6   y5   y4   y3   y2   y1   y0
  byte 5:  0   z6   z5   z4   z3   z2   z1   z0
 
+Protocol Version 2 DualPoint devices send standard PS/2 mouse packets for
+the DualPoint Stick.
+
 Dualpoint device -- interleaved packet format
 ---------------------------------------------
 
@@ -127,6 +130,11 @@ Dualpoint device -- interleaved packet format
  byte 7:    0   y6   y5   y4   y3   y2   y1   y0
  byte 8:    0   z6   z5   z4   z3   z2   z1   z0
 
+Devices which use the interleaving format normally send standard PS/2 mouse
+packets for the DualPoint Stick + ALPS Absolute Mode packets for the
+touchpad, switching to the interleaved packet format when both the stick and
+the touchpad are used at the same time.
+
 ALPS Absolute Mode - Protocol Version 3
 ---------------------------------------
 
index c587a966413e8597da3241f851db92f6e6df1d81..96705616f5820a6d48d6cfda497c7fcf30917e2a 100644 (file)
@@ -294,6 +294,12 @@ accordingly. This property does not affect kernel behavior.
 The kernel does not provide button emulation for such devices but treats
 them as any other INPUT_PROP_BUTTONPAD device.
 
+INPUT_PROP_ACCELEROMETER
+-------------------------
+Directional axes on this device (absolute and/or relative x, y, z) represent
+accelerometer data. All other axes retain their meaning. A device must not mix
+regular directional axes and accelerometer axes on the same event node.
+
 Guidelines:
 ==========
 The guidelines below ensure proper single-touch and multi-finger functionality.
index 7b4f59c09ee2301d077446f5f9ce9c2b96aa2551..b85d000faeb4067c9ab1ed06690105d459a40a4e 100644 (file)
@@ -312,9 +312,12 @@ ABS_MT_TOOL_TYPE
 
 The type of approaching tool. A lot of kernel drivers cannot distinguish
 between different tool types, such as a finger or a pen. In such cases, the
-event should be omitted. The protocol currently supports MT_TOOL_FINGER and
-MT_TOOL_PEN [2]. For type B devices, this event is handled by input core;
-drivers should instead use input_mt_report_slot_state().
+event should be omitted. The protocol currently supports MT_TOOL_FINGER,
+MT_TOOL_PEN, and MT_TOOL_PALM [2]. For type B devices, this event is handled
+by input core; drivers should instead use input_mt_report_slot_state().
+A contact's ABS_MT_TOOL_TYPE may change over time while still touching the
+device, because the firmware may not be able to determine which tool is being
+used when it first appears.
 
 ABS_MT_BLOB_ID
 
index 1de6afa8ee51c747b592e6a10fce1cf742d2bc96..652004223eadc99a0249dcc6eb8742d09342db40 100644 (file)
@@ -637,8 +637,7 @@ 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
+M:     Borislav Petkov <bp@alien8.de>
 S:     Maintained
 F:     arch/x86/kernel/cpu/microcode/amd*
 
@@ -3397,7 +3396,6 @@ T:        git git://people.freedesktop.org/~airlied/linux
 S:     Supported
 F:     drivers/gpu/drm/rcar-du/
 F:     drivers/gpu/drm/shmobile/
-F:     include/linux/platform_data/rcar-du.h
 F:     include/linux/platform_data/shmob_drm.h
 
 DSBR100 USB FM RADIO DRIVER
@@ -5095,7 +5093,7 @@ S:        Supported
 F:     drivers/platform/x86/intel_menlow.c
 
 INTEL IA32 MICROCODE UPDATE SUPPORT
-M:     Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+M:     Borislav Petkov <bp@alien8.de>
 S:     Maintained
 F:     arch/x86/kernel/cpu/microcode/core*
 F:     arch/x86/kernel/cpu/microcode/intel*
@@ -5136,22 +5134,21 @@ M:      Deepak Saxena <dsaxena@plexity.net>
 S:     Maintained
 F:     drivers/char/hw_random/ixp4xx-rng.c
 
-INTEL ETHERNET DRIVERS (e100/e1000/e1000e/fm10k/igb/igbvf/ixgb/ixgbe/ixgbevf/i40e/i40evf)
+INTEL ETHERNET DRIVERS
 M:     Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-M:     Jesse Brandeburg <jesse.brandeburg@intel.com>
-M:     Bruce Allan <bruce.w.allan@intel.com>
-M:     Carolyn Wyborny <carolyn.wyborny@intel.com>
-M:     Don Skidmore <donald.c.skidmore@intel.com>
-M:     Greg Rose <gregory.v.rose@intel.com>
-M:     Matthew Vick <matthew.vick@intel.com>
-M:     John Ronciak <john.ronciak@intel.com>
-M:     Mitch Williams <mitch.a.williams@intel.com>
-M:     Linux NICS <linux.nics@intel.com>
-L:     e1000-devel@lists.sourceforge.net
+R:     Jesse Brandeburg <jesse.brandeburg@intel.com>
+R:     Shannon Nelson <shannon.nelson@intel.com>
+R:     Carolyn Wyborny <carolyn.wyborny@intel.com>
+R:     Don Skidmore <donald.c.skidmore@intel.com>
+R:     Matthew Vick <matthew.vick@intel.com>
+R:     John Ronciak <john.ronciak@intel.com>
+R:     Mitch Williams <mitch.a.williams@intel.com>
+L:     intel-wired-lan@lists.osuosl.org
 W:     http://www.intel.com/support/feedback.htm
 W:     http://e1000.sourceforge.net/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next.git
+Q:     http://patchwork.ozlabs.org/project/intel-wired-lan/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-queue.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue.git
 S:     Supported
 F:     Documentation/networking/e100.txt
 F:     Documentation/networking/e1000.txt
@@ -7195,6 +7192,15 @@ F:       Documentation/devicetree/
 F:     arch/*/boot/dts/
 F:     include/dt-bindings/
 
+OPEN FIRMWARE AND DEVICE TREE OVERLAYS
+M:     Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+L:     devicetree@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/dynamic-resolution-notes.txt
+F:     Documentation/devicetree/overlay-notes.txt
+F:     drivers/of/overlay.c
+F:     drivers/of/resolver.c
+
 OPENRISC ARCHITECTURE
 M:     Jonas Bonn <jonas@southpole.se>
 W:     http://openrisc.net
index da36a3be7969049870d969ae4a623fd7a0c15ee1..54430f933b628ca99bdbc1e2bf5dd2570ca0354c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 4
 PATCHLEVEL = 0
 SUBLEVEL = 0
-EXTRAVERSION = -rc6
+EXTRAVERSION = -rc7
 NAME = Hurr durr I'ma sheep
 
 # *DOCUMENTATION*
index 2bf8e9307be9833b5bf9af51defdfada8feae68d..4c8ad592ae3351d96f7e225411d9f551657c5bc7 100644 (file)
@@ -55,7 +55,7 @@ static inline cpumask_t cpu_thread_mask_to_cores(const struct cpumask *threads)
 
 static inline int cpu_nr_cores(void)
 {
-       return NR_CPUS >> threads_shift;
+       return nr_cpu_ids >> threads_shift;
 }
 
 static inline cpumask_t cpu_online_cores_map(void)
index 498b6d967138b1fff29659e81813c77e70ff1f58..258990688a5e999557de7f3b5398d7eccdc45ebb 100644 (file)
@@ -212,11 +212,11 @@ static struct event_constraint intel_hsw_event_constraints[] = {
        INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */
        INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */
        /* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */
-       INTEL_EVENT_CONSTRAINT(0x08a3, 0x4),
+       INTEL_UEVENT_CONSTRAINT(0x08a3, 0x4),
        /* CYCLE_ACTIVITY.STALLS_L1D_PENDING */
-       INTEL_EVENT_CONSTRAINT(0x0ca3, 0x4),
+       INTEL_UEVENT_CONSTRAINT(0x0ca3, 0x4),
        /* CYCLE_ACTIVITY.CYCLES_NO_EXECUTE */
-       INTEL_EVENT_CONSTRAINT(0x04a3, 0xf),
+       INTEL_UEVENT_CONSTRAINT(0x04a3, 0xf),
        EVENT_CONSTRAINT_END
 };
 
@@ -1649,11 +1649,11 @@ intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event
        if (c)
                return c;
 
-       c = intel_pebs_constraints(event);
+       c = intel_shared_regs_constraints(cpuc, event);
        if (c)
                return c;
 
-       c = intel_shared_regs_constraints(cpuc, event);
+       c = intel_pebs_constraints(event);
        if (c)
                return c;
 
index 2babb393915e76dbeb8a1b757305b819fddd324b..f0095a76c18211813d711bfa52b82c916190f42d 100644 (file)
@@ -799,7 +799,21 @@ retint_swapgs:             /* return to user-space */
        cmpq %r11,(EFLAGS-ARGOFFSET)(%rsp)      /* R11 == RFLAGS */
        jne opportunistic_sysret_failed
 
-       testq $X86_EFLAGS_RF,%r11               /* sysret can't restore RF */
+       /*
+        * SYSRET can't restore RF.  SYSRET can restore TF, but unlike IRET,
+        * restoring TF results in a trap from userspace immediately after
+        * SYSRET.  This would cause an infinite loop whenever #DB happens
+        * with register state that satisfies the opportunistic SYSRET
+        * conditions.  For example, single-stepping this user code:
+        *
+        *           movq $stuck_here,%rcx
+        *           pushfq
+        *           popq %r11
+        *   stuck_here:
+        *
+        * would never get past 'stuck_here'.
+        */
+       testq $(X86_EFLAGS_RF|X86_EFLAGS_TF), %r11
        jnz opportunistic_sysret_failed
 
        /* nothing to check for RSP */
index 7ec1d5f8d28339bce0b74191a1d458c6c8e5d5df..25ecd56cefa8f22496153cf29b763c266bd8d91e 100644 (file)
@@ -72,7 +72,7 @@ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
        { "bx", 8, offsetof(struct pt_regs, bx) },
        { "cx", 8, offsetof(struct pt_regs, cx) },
        { "dx", 8, offsetof(struct pt_regs, dx) },
-       { "si", 8, offsetof(struct pt_regs, dx) },
+       { "si", 8, offsetof(struct pt_regs, si) },
        { "di", 8, offsetof(struct pt_regs, di) },
        { "bp", 8, offsetof(struct pt_regs, bp) },
        { "sp", 8, offsetof(struct pt_regs, sp) },
index bae6c609888e7fdff25784d5bd96fd8dcd5ea88a..86db4bcd7ce52bcb74a5bf42efcd8e7152488cf1 100644 (file)
@@ -183,6 +183,16 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                },
        },
 
+       /* ASRock */
+       {       /* Handle problems with rebooting on ASRock Q1900DC-ITX */
+               .callback = set_pci_reboot,
+               .ident = "ASRock Q1900DC-ITX",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASRock"),
+                       DMI_MATCH(DMI_BOARD_NAME, "Q1900DC-ITX"),
+               },
+       },
+
        /* ASUS */
        {       /* Handle problems with rebooting on ASUS P4S800 */
                .callback = set_bios_reboot,
index 9f93af56a5fc7bd4cf263406faf96f8a5fa56466..b47124d4cd67e29199fae1c48f9a94ecd93b00f7 100644 (file)
@@ -91,6 +91,12 @@ EXPORT_SYMBOL_GPL(xen_p2m_size);
 unsigned long xen_max_p2m_pfn __read_mostly;
 EXPORT_SYMBOL_GPL(xen_max_p2m_pfn);
 
+#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG_LIMIT
+#define P2M_LIMIT CONFIG_XEN_BALLOON_MEMORY_HOTPLUG_LIMIT
+#else
+#define P2M_LIMIT 0
+#endif
+
 static DEFINE_SPINLOCK(p2m_update_lock);
 
 static unsigned long *p2m_mid_missing_mfn;
@@ -385,9 +391,11 @@ static void __init xen_rebuild_p2m_list(unsigned long *p2m)
 void __init xen_vmalloc_p2m_tree(void)
 {
        static struct vm_struct vm;
+       unsigned long p2m_limit;
 
+       p2m_limit = (phys_addr_t)P2M_LIMIT * 1024 * 1024 * 1024 / PAGE_SIZE;
        vm.flags = VM_ALLOC;
-       vm.size = ALIGN(sizeof(unsigned long) * xen_max_p2m_pfn,
+       vm.size = ALIGN(sizeof(unsigned long) * max(xen_max_p2m_pfn, p2m_limit),
                        PMD_SIZE * PMDS_PER_MID_PAGE);
        vm_area_register_early(&vm, PMD_SIZE * PMDS_PER_MID_PAGE);
        pr_notice("p2m virtual area at %p, size is %lx\n", vm.addr, vm.size);
index 6ed2cbe5e8c9ae340233b0491255dfed40947590..12600bfffca93f4547e2325eeda9669ff443a7a7 100644 (file)
@@ -585,7 +585,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                                     b->physical_block_size);
 
        t->io_min = max(t->io_min, b->io_min);
-       t->io_opt = lcm(t->io_opt, b->io_opt);
+       t->io_opt = lcm_not_zero(t->io_opt, b->io_opt);
 
        t->cluster &= b->cluster;
        t->discard_zeroes_data &= b->discard_zeroes_data;
@@ -616,7 +616,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                    b->raid_partial_stripes_expensive);
 
        /* Find lowest common alignment_offset */
-       t->alignment_offset = lcm(t->alignment_offset, alignment)
+       t->alignment_offset = lcm_not_zero(t->alignment_offset, alignment)
                % max(t->physical_block_size, t->io_min);
 
        /* Verify that new alignment_offset is on a logical block boundary */
@@ -643,7 +643,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                                                      b->max_discard_sectors);
                t->discard_granularity = max(t->discard_granularity,
                                             b->discard_granularity);
-               t->discard_alignment = lcm(t->discard_alignment, alignment) %
+               t->discard_alignment = lcm_not_zero(t->discard_alignment, alignment) %
                        t->discard_granularity;
        }
 
index ef150ebb4c304efa1cbf5fb6e23a2a9da036ae91..23dac3babfe3afc710db73a2ad4f8fe05174b7d7 100644 (file)
@@ -4204,9 +4204,18 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "PIONEER DVD-RW  DVR-216D",   NULL,   ATA_HORKAGE_NOSETXFER },
 
        /* devices that don't properly handle queued TRIM commands */
-       { "Micron_M[56]*",              NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
+       { "Micron_M500*",               NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Crucial_CT*M500*",           NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Micron_M5[15]0*",            "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Crucial_CT*M550*",           "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Crucial_CT*MX100*",          "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Samsung SSD 850 PRO*",       NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
                                                ATA_HORKAGE_ZERO_AFTER_TRIM, },
-       { "Crucial_CT*SSD*",            NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
 
        /*
         * As defined, the DRAT (Deterministic Read After Trim) and RZAT
@@ -4226,6 +4235,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
         */
        { "INTEL*SSDSC2MH*",            NULL,   0, },
 
+       { "Micron*",                    NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Crucial*",                   NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
        { "INTEL*SSD*",                 NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
        { "SSD*INTEL*",                 NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
        { "Samsung*SSD*",               NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
index c3efa418a86d8eda8f715cecd97382deb965a8e8..6f75e9d5b6fb0755d41b3e252daea83179efb4b6 100644 (file)
@@ -52,15 +52,6 @@ of_coresight_get_endpoint_device(struct device_node *endpoint)
                               endpoint, of_dev_node_match);
 }
 
-static struct device_node *of_get_coresight_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;
-}
-
 static void of_coresight_get_ports(struct device_node *node,
                                   int *nr_inport, int *nr_outport)
 {
@@ -68,7 +59,7 @@ static void of_coresight_get_ports(struct device_node *node,
        int in = 0, out = 0;
 
        do {
-               ep = of_get_coresight_endpoint(node, ep);
+               ep = of_graph_get_next_endpoint(node, ep);
                if (!ep)
                        break;
 
@@ -140,7 +131,7 @@ struct coresight_platform_data *of_get_coresight_platform_data(
                /* Iterate through each port to discover topology */
                do {
                        /* Get a handle on a port */
-                       ep = of_get_coresight_endpoint(node, ep);
+                       ep = of_graph_get_next_endpoint(node, ep);
                        if (!ep)
                                break;
 
index 0723096fb50ac125dbb471126ba396085307ff2e..c92d6a70ccf303c69cfdb127210a09a1262122bc 100644 (file)
@@ -475,6 +475,7 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan)
         * c->desc is NULL and exit.)
         */
        if (c->desc) {
+               bcm2835_dma_desc_free(&c->desc->vd);
                c->desc = NULL;
                bcm2835_dma_abort(c->chan_base);
 
index 4527a3ebeac446f58a4c3b3b8722d6caf16b1b63..84884418fd30fc73a700bde9c0bebd67d72ea0a5 100644 (file)
@@ -511,6 +511,9 @@ static void jz4740_dma_desc_free(struct virt_dma_desc *vdesc)
        kfree(container_of(vdesc, struct jz4740_dma_desc, vdesc));
 }
 
+#define JZ4740_DMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+       BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
+
 static int jz4740_dma_probe(struct platform_device *pdev)
 {
        struct jz4740_dmaengine_chan *chan;
@@ -548,6 +551,10 @@ static int jz4740_dma_probe(struct platform_device *pdev)
        dd->device_prep_dma_cyclic = jz4740_dma_prep_dma_cyclic;
        dd->device_config = jz4740_dma_slave_config;
        dd->device_terminate_all = jz4740_dma_terminate_all;
+       dd->src_addr_widths = JZ4740_DMA_BUSWIDTHS;
+       dd->dst_addr_widths = JZ4740_DMA_BUSWIDTHS;
+       dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
        dd->dev = &pdev->dev;
        INIT_LIST_HEAD(&dd->channels);
 
index 276157f22612dc18140b84294ab1ef49ecf46ebc..53dbd3b3384cfd8b00940f7a7cd752b28bcac71a 100644 (file)
@@ -260,6 +260,13 @@ static int edma_terminate_all(struct dma_chan *chan)
         */
        if (echan->edesc) {
                int cyclic = echan->edesc->cyclic;
+
+               /*
+                * free the running request descriptor
+                * since it is not in any of the vdesc lists
+                */
+               edma_desc_free(&echan->edesc->vdesc);
+
                echan->edesc = NULL;
                edma_stop(echan->ch_num);
                /* Move the cyclic channel back to default queue */
index 15cab7d79525914d862e5cd38344bc2e3046c95a..b4634109e0100905dd39d285f03d669c405cbef0 100644 (file)
@@ -193,8 +193,10 @@ static int moxart_terminate_all(struct dma_chan *chan)
 
        spin_lock_irqsave(&ch->vc.lock, flags);
 
-       if (ch->desc)
+       if (ch->desc) {
+               moxart_dma_desc_free(&ch->desc->vd);
                ch->desc = NULL;
+       }
 
        ctrl = readl(ch->base + REG_OFF_CTRL);
        ctrl &= ~(APB_DMA_ENABLE | APB_DMA_FIN_INT_EN | APB_DMA_ERR_INT_EN);
index 7dd6dd1216819543aae06f2d3dd2707d16917c24..167dbaf6574275a0fffd5590b7a169e811320b39 100644 (file)
@@ -981,6 +981,7 @@ static int omap_dma_terminate_all(struct dma_chan *chan)
         * c->desc is NULL and exit.)
         */
        if (c->desc) {
+               omap_dma_desc_free(&c->desc->vd);
                c->desc = NULL;
                /* Avoid stopping the dma twice */
                if (!c->paused)
index 69fac068669fde566f41013cefbdf48db023466c..2eebd28b4c40af2789c32e0008f2b60006fc03ac 100644 (file)
@@ -86,10 +86,13 @@ static void dmi_table(u8 *buf, u32 len, int num,
        int i = 0;
 
        /*
-        *      Stop when we see all the items the table claimed to have
-        *      OR we run off the end of the table (also happens)
+        * Stop when we have seen all the items the table claimed to have
+        * (SMBIOS < 3.0 only) OR we reach an end-of-table marker OR we run
+        * off the end of the table (should never happen but sometimes does
+        * on bogus implementations.)
         */
-       while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) {
+       while ((!num || i < num) &&
+              (data - buf + sizeof(struct dmi_header)) <= len) {
                const struct dmi_header *dm = (const struct dmi_header *)data;
 
                /*
@@ -529,21 +532,10 @@ static int __init dmi_smbios3_present(const u8 *buf)
        if (memcmp(buf, "_SM3_", 5) == 0 &&
            buf[6] < 32 && dmi_checksum(buf, buf[6])) {
                dmi_ver = get_unaligned_be16(buf + 7);
+               dmi_num = 0;                    /* No longer specified */
                dmi_len = get_unaligned_le32(buf + 12);
                dmi_base = get_unaligned_le64(buf + 16);
 
-               /*
-                * The 64-bit SMBIOS 3.0 entry point no longer has a field
-                * containing the number of structures present in the table.
-                * Instead, it defines the table size as a maximum size, and
-                * relies on the end-of-table structure type (#127) to be used
-                * to signal the end of the table.
-                * So let's define dmi_num as an upper bound as well: each
-                * structure has a 4 byte header, so dmi_len / 4 is an upper
-                * bound for the number of structures in the table.
-                */
-               dmi_num = dmi_len / 4;
-
                if (dmi_walk_early(dmi_decode) == 0) {
                        pr_info("SMBIOS %d.%d present.\n",
                                dmi_ver >> 8, dmi_ver & 0xFF);
index a6952ba343a89747b919b45aa4d9e07951762fcd..a65b75161aa49d16749258407db18c7cfc30f79f 100644 (file)
@@ -334,7 +334,7 @@ static struct irq_domain_ops mpc8xxx_gpio_irq_ops = {
        .xlate  = irq_domain_xlate_twocell,
 };
 
-static struct of_device_id mpc8xxx_gpio_ids[] __initdata = {
+static struct of_device_id mpc8xxx_gpio_ids[] = {
        { .compatible = "fsl,mpc8349-gpio", },
        { .compatible = "fsl,mpc8572-gpio", },
        { .compatible = "fsl,mpc8610-gpio", },
index 257e2989215c035b87fbef2f7b086c58b722e266..045a952576c708e253de29438abaec95640989f2 100644 (file)
@@ -219,7 +219,7 @@ static int syscon_gpio_probe(struct platform_device *pdev)
                ret = of_property_read_u32_index(np, "gpio,syscon-dev", 2,
                                                 &priv->dir_reg_offset);
                if (ret)
-                       dev_err(dev, "can't read the dir register offset!\n");
+                       dev_dbg(dev, "can't read the dir register offset!\n");
 
                priv->dir_reg_offset <<= 3;
        }
index c0929d938ced866e343e0230e00fc5c9cda77c0b..df990f29757a7e045fd8a42760944b2d8bd2ba84 100644 (file)
@@ -201,6 +201,10 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
        if (!handler)
                return AE_BAD_PARAMETER;
 
+       pin = acpi_gpiochip_pin_to_gpio_offset(chip, pin);
+       if (pin < 0)
+               return AE_BAD_PARAMETER;
+
        desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event");
        if (IS_ERR(desc)) {
                dev_err(chip->dev, "Failed to request GPIO\n");
@@ -551,6 +555,12 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
                struct gpio_desc *desc;
                bool found;
 
+               pin = acpi_gpiochip_pin_to_gpio_offset(chip, pin);
+               if (pin < 0) {
+                       status = AE_BAD_PARAMETER;
+                       goto out;
+               }
+
                mutex_lock(&achip->conn_lock);
 
                found = false;
index 151a050129e761ce5b10700020dcc47626196918..47f2ce81b4120d64c7c0dcff8d3541a0eeacc7be 100644 (file)
@@ -165,6 +165,15 @@ config DRM_SAVAGE
          Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
          chipset. If M is selected the module will be called savage.
 
+config DRM_VGEM
+       tristate "Virtual GEM provider"
+       depends on DRM
+       help
+         Choose this option to get a virtual graphics memory manager,
+         as used by Mesa's software renderer for enhanced performance.
+         If M is selected the module will be called vgem.
+
+
 source "drivers/gpu/drm/exynos/Kconfig"
 
 source "drivers/gpu/drm/rockchip/Kconfig"
index 2c239b99de64256c588dc94a457adaf6e1d3eded..7d4944e1a60c740abf718cf5ea68eaab48aa084c 100644 (file)
@@ -48,6 +48,7 @@ obj-$(CONFIG_DRM_SIS)   += sis/
 obj-$(CONFIG_DRM_SAVAGE)+= savage/
 obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
 obj-$(CONFIG_DRM_VIA)  +=via/
+obj-$(CONFIG_DRM_VGEM) += vgem/
 obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
 obj-$(CONFIG_DRM_EXYNOS) +=exynos/
 obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
index 5c50aa8a8908379980b299ad12fd3868c23fb70c..19a4fba46e4e26ea4e31044b597e0f50f45fb9fd 100644 (file)
@@ -435,21 +435,22 @@ static int kfd_ioctl_get_clock_counters(struct file *filep,
 {
        struct kfd_ioctl_get_clock_counters_args *args = data;
        struct kfd_dev *dev;
-       struct timespec time;
+       struct timespec64 time;
 
        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);
+       args->gpu_clock_counter =
+               dev->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);
+       getrawmonotonic64(&time);
+       args->cpu_clock_counter = (uint64_t)timespec64_to_ns(&time);
 
-       get_monotonic_boottime(&time);
-       args->system_clock_counter = (uint64_t)timespec_to_ns(&time);
+       get_monotonic_boottime64(&time);
+       args->system_clock_counter = (uint64_t)timespec64_to_ns(&time);
 
        /* Since the counter is in nano-seconds we use 1GHz frequency */
        args->system_clock_freq = 1000000000;
index 5bc32c26b9890eb1f1bf2cf70b1d7e7822bf64fc..ca7f2d3af2ff048301864158b4df492b5e43eb1e 100644 (file)
@@ -94,7 +94,8 @@ static const struct kfd_device_info *lookup_device_info(unsigned short did)
        return NULL;
 }
 
-struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev)
+struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd,
+       struct pci_dev *pdev, const struct kfd2kgd_calls *f2g)
 {
        struct kfd_dev *kfd;
 
@@ -112,6 +113,11 @@ struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev)
        kfd->device_info = device_info;
        kfd->pdev = pdev;
        kfd->init_complete = false;
+       kfd->kfd2kgd = f2g;
+
+       mutex_init(&kfd->doorbell_mutex);
+       memset(&kfd->doorbell_available_index, 0,
+               sizeof(kfd->doorbell_available_index));
 
        return kfd;
 }
@@ -200,8 +206,9 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
        /* add another 512KB for all other allocations on gart (HPD, fences) */
        size += 512 * 1024;
 
-       if (kfd2kgd->init_gtt_mem_allocation(kfd->kgd, size, &kfd->gtt_mem,
-                       &kfd->gtt_start_gpu_addr, &kfd->gtt_start_cpu_ptr)) {
+       if (kfd->kfd2kgd->init_gtt_mem_allocation(
+                       kfd->kgd, size, &kfd->gtt_mem,
+                       &kfd->gtt_start_gpu_addr, &kfd->gtt_start_cpu_ptr)){
                dev_err(kfd_device,
                        "Could not allocate %d bytes for device (%x:%x)\n",
                        size, kfd->pdev->vendor, kfd->pdev->device);
@@ -270,7 +277,7 @@ device_iommu_pasid_error:
 kfd_topology_add_device_error:
        kfd_gtt_sa_fini(kfd);
 kfd_gtt_sa_init_error:
-       kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
+       kfd->kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
        dev_err(kfd_device,
                "device (%x:%x) NOT added due to errors\n",
                kfd->pdev->vendor, kfd->pdev->device);
@@ -285,7 +292,7 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd)
                amd_iommu_free_device(kfd->pdev);
                kfd_topology_remove_device(kfd);
                kfd_gtt_sa_fini(kfd);
-               kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
+               kfd->kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
        }
 
        kfree(kfd);
index d8135adb2238012460cfb67165d0f322f809230a..69af73f153103075f00c9344f836bd7eb3b24668 100644 (file)
@@ -82,7 +82,8 @@ static inline unsigned int get_pipes_num_cpsch(void)
 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,
+       return dqm->dev->kfd2kgd->program_sh_mem_settings(
+                                               dqm->dev->kgd, qpd->vmid,
                                                qpd->sh_mem_config,
                                                qpd->sh_mem_ape1_base,
                                                qpd->sh_mem_ape1_limit,
@@ -457,9 +458,12 @@ set_pasid_vmid_mapping(struct device_queue_manager *dqm, unsigned int pasid,
 {
        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,
+       pasid_mapping = (pasid == 0) ? 0 :
+               (uint32_t)pasid |
+               ATC_VMID_PASID_MAPPING_VALID;
+
+       return dqm->dev->kfd2kgd->set_pasid_vmid_mapping(
+                                               dqm->dev->kgd, pasid_mapping,
                                                vmid);
 }
 
@@ -511,7 +515,7 @@ int init_pipelines(struct device_queue_manager *dqm,
                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, inx,
+               dqm->dev->kfd2kgd->init_pipeline(dqm->dev->kgd, inx,
                                CIK_HPD_EOP_BYTES_LOG2 - 3, pipe_hpd_addr);
        }
 
@@ -905,7 +909,7 @@ out:
        return retval;
 }
 
-static int fence_wait_timeout(unsigned int *fence_addr,
+static int amdkfd_fence_wait_timeout(unsigned int *fence_addr,
                                unsigned int fence_value,
                                unsigned long timeout)
 {
@@ -961,7 +965,7 @@ static int destroy_queues_cpsch(struct device_queue_manager *dqm, bool lock)
        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,
+       amdkfd_fence_wait_timeout(dqm->fence_addr, KFD_FENCE_COMPLETED,
                                QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS);
        pm_release_ib(&dqm->packets);
        dqm->active_runlist = false;
index 1a9b355dd114595f8bcf156907e486ebe2bbbdb4..17e56dcc8540ff8bbb8e18599094dd49405c9ccf 100644 (file)
@@ -32,9 +32,6 @@
  * 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
@@ -170,12 +167,12 @@ u32 __iomem *kfd_get_kernel_doorbell(struct kfd_dev *kfd,
 
        BUG_ON(!kfd || !doorbell_off);
 
-       mutex_lock(&doorbell_mutex);
-       inx = find_first_zero_bit(doorbell_available_index,
+       mutex_lock(&kfd->doorbell_mutex);
+       inx = find_first_zero_bit(kfd->doorbell_available_index,
                                        KFD_MAX_NUM_OF_QUEUES_PER_PROCESS);
 
-       __set_bit(inx, doorbell_available_index);
-       mutex_unlock(&doorbell_mutex);
+       __set_bit(inx, kfd->doorbell_available_index);
+       mutex_unlock(&kfd->doorbell_mutex);
 
        if (inx >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)
                return NULL;
@@ -203,9 +200,9 @@ void kfd_release_kernel_doorbell(struct kfd_dev *kfd, u32 __iomem *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);
+       mutex_lock(&kfd->doorbell_mutex);
+       __clear_bit(inx, kfd->doorbell_available_index);
+       mutex_unlock(&kfd->doorbell_mutex);
 }
 
 inline void write_kernel_doorbell(u32 __iomem *db, u32 value)
index 3f34ae16f0750a04365c75cf448d66574e16e9b6..4e0a68f13a77bc4153256161224c0ab4fc3cf5bc 100644 (file)
@@ -34,7 +34,6 @@
 #define KFD_DRIVER_MINOR       7
 #define KFD_DRIVER_PATCHLEVEL  1
 
-const struct kfd2kgd_calls *kfd2kgd;
 static const struct kgd2kfd_calls kgd2kfd = {
        .exit           = kgd2kfd_exit,
        .probe          = kgd2kfd_probe,
@@ -55,9 +54,7 @@ module_param(max_num_of_queues_per_device, int, 0444);
 MODULE_PARM_DESC(max_num_of_queues_per_device,
        "Maximum number of supported queues per device (1 = Minimum, 4096 = default)");
 
-bool kgd2kfd_init(unsigned interface_version,
-                 const struct kfd2kgd_calls *f2g,
-                 const struct kgd2kfd_calls **g2f)
+bool kgd2kfd_init(unsigned interface_version, const struct kgd2kfd_calls **g2f)
 {
        /*
         * Only one interface version is supported,
@@ -66,11 +63,6 @@ bool kgd2kfd_init(unsigned interface_version,
        if (interface_version != KFD_INTERFACE_VERSION)
                return false;
 
-       /* Protection against multiple amd kgd loads */
-       if (kfd2kgd)
-               return true;
-
-       kfd2kgd = f2g;
        *g2f = &kgd2kfd;
 
        return true;
@@ -85,8 +77,6 @@ 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)) {
index a09e18a339f34ef1268ce9ccd8c6ef0804c9ff76..434979428fc01264647b6189d41aea235d4fda4b 100644 (file)
@@ -151,14 +151,15 @@ static void uninit_mqd_sdma(struct mqd_manager *mm, void *mqd,
 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);
+       return mm->dev->kfd2kgd->hqd_load
+               (mm->dev->kgd, mqd, pipe_id, queue_id, wptr);
 }
 
 static int load_mqd_sdma(struct mqd_manager *mm, void *mqd,
                        uint32_t pipe_id, uint32_t queue_id,
                        uint32_t __user *wptr)
 {
-       return kfd2kgd->hqd_sdma_load(mm->dev->kgd, mqd);
+       return mm->dev->kfd2kgd->hqd_sdma_load(mm->dev->kgd, mqd);
 }
 
 static int update_mqd(struct mqd_manager *mm, void *mqd,
@@ -245,7 +246,7 @@ static int destroy_mqd(struct mqd_manager *mm, void *mqd,
                        unsigned int timeout, uint32_t pipe_id,
                        uint32_t queue_id)
 {
-       return kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout,
+       return mm->dev->kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout,
                                        pipe_id, queue_id);
 }
 
@@ -258,7 +259,7 @@ static int destroy_mqd_sdma(struct mqd_manager *mm, void *mqd,
                                unsigned int timeout, uint32_t pipe_id,
                                uint32_t queue_id)
 {
-       return kfd2kgd->hqd_sdma_destroy(mm->dev->kgd, mqd, timeout);
+       return mm->dev->kfd2kgd->hqd_sdma_destroy(mm->dev->kgd, mqd, timeout);
 }
 
 static bool is_occupied(struct mqd_manager *mm, void *mqd,
@@ -266,7 +267,7 @@ static bool is_occupied(struct mqd_manager *mm, void *mqd,
                        uint32_t queue_id)
 {
 
-       return kfd2kgd->hqd_is_occupied(mm->dev->kgd, queue_address,
+       return mm->dev->kfd2kgd->hqd_is_occupied(mm->dev->kgd, queue_address,
                                        pipe_id, queue_id);
 
 }
@@ -275,7 +276,7 @@ static bool is_occupied_sdma(struct mqd_manager *mm, void *mqd,
                        uint64_t queue_address, uint32_t pipe_id,
                        uint32_t queue_id)
 {
-       return kfd2kgd->hqd_sdma_is_occupied(mm->dev->kgd, mqd);
+       return mm->dev->kfd2kgd->hqd_sdma_is_occupied(mm->dev->kgd, mqd);
 }
 
 /*
index 5a44f2fecf3826b7b90e18cf3d22b7f64c113a26..f21fccebd75b2bd082a6b3c6c45aa6cd7353ef5d 100644 (file)
@@ -148,6 +148,11 @@ struct kfd_dev {
 
        struct kgd2kfd_shared_resources shared_resources;
 
+       const struct kfd2kgd_calls *kfd2kgd;
+       struct mutex doorbell_mutex;
+       unsigned long doorbell_available_index[DIV_ROUND_UP(
+               KFD_MAX_NUM_OF_QUEUES_PER_PROCESS, BITS_PER_LONG)];
+
        void *gtt_mem;
        uint64_t gtt_start_gpu_addr;
        void *gtt_start_cpu_ptr;
@@ -164,13 +169,12 @@ struct kfd_dev {
 
 /* KGD2KFD callbacks */
 void kgd2kfd_exit(void);
-struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev);
+struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd,
+                       struct pci_dev *pdev, const struct kfd2kgd_calls *f2g);
 bool kgd2kfd_device_init(struct kfd_dev *kfd,
-                        const struct kgd2kfd_shared_resources *gpu_resources);
+                       const struct kgd2kfd_shared_resources *gpu_resources);
 void kgd2kfd_device_exit(struct kfd_dev *kfd);
 
-extern const struct kfd2kgd_calls *kfd2kgd;
-
 enum kfd_mempool {
        KFD_MEMPOOL_SYSTEM_CACHEABLE = 1,
        KFD_MEMPOOL_SYSTEM_WRITECOMBINE = 2,
@@ -378,8 +382,6 @@ 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;
index a369c149d1727e78cb67413578e6fe7ddd11d614..945d6226dc51d5b9b55e6af19229a5a9e872f802 100644 (file)
@@ -162,10 +162,16 @@ static void kfd_process_wq_release(struct work_struct *work)
 
        p = my_work->p;
 
+       pr_debug("Releasing process (pasid %d) in workqueue\n",
+                       p->pasid);
+
        mutex_lock(&p->mutex);
 
        list_for_each_entry_safe(pdd, temp, &p->per_device_data,
                                                        per_device_list) {
+               pr_debug("Releasing pdd (topology id %d) for process (pasid %d) in workqueue\n",
+                               pdd->dev->id, p->pasid);
+
                amd_iommu_unbind_pasid(pdd->dev->pdev, p->pasid);
                list_del(&pdd->per_device_list);
 
index 498399323a8cd503f35fb3e828abf08c2368cad8..661c6605d31b39033a42a5d4297e1684ed734011 100644 (file)
@@ -726,13 +726,14 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
                }
 
                sysfs_show_32bit_prop(buffer, "max_engine_clk_fcompute",
-                               kfd2kgd->get_max_engine_clock_in_mhz(
+                       dev->gpu->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));
+                       dev->gpu->kfd2kgd->get_vmem_size(
+                                       dev->gpu->kgd));
 
                sysfs_show_32bit_prop(buffer, "fw_version",
-                               kfd2kgd->get_fw_version(
+                       dev->gpu->kfd2kgd->get_fw_version(
                                                dev->gpu->kgd,
                                                KGD_ENGINE_MEC1));
        }
@@ -1099,8 +1100,9 @@ static uint32_t kfd_generate_gpu_id(struct kfd_dev *gpu)
        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);
+       buf[5] = (uint32_t)(gpu->kfd2kgd->get_vmem_size(gpu->kgd)
+                       & 0xffffffff);
+       buf[6] = (uint32_t)(gpu->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);
index 239bc16a1ddd61c9fd65d3d1f1284025fd69df2c..dabd94446b7b2a5d771cd7a2cc704d73cddff087 100644 (file)
@@ -76,37 +76,6 @@ struct kgd2kfd_shared_resources {
        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
  *
@@ -196,8 +165,39 @@ struct kfd2kgd_calls {
                                enum kgd_engine_type type);
 };
 
+/**
+ * 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,
+               const struct kfd2kgd_calls *f2g);
+       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);
+};
+
 bool kgd2kfd_init(unsigned interface_version,
-               const struct kfd2kgd_calls *f2g,
                const struct kgd2kfd_calls **g2f);
 
 #endif /* KGD_KFD_INTERFACE_H_INCLUDED */
index 4126d43b5057a0a8b7d17a9eeb97f46b820bc63e..3c4023e142d06fab06665d07b691b50db91a1cd0 100644 (file)
@@ -9,7 +9,7 @@
 #define ARMADA_CONNETOR_H
 
 #define encoder_helper_funcs(encoder) \
-       ((struct drm_encoder_helper_funcs *)encoder->helper_private)
+       ((const struct drm_encoder_helper_funcs *)encoder->helper_private)
 
 struct armada_output_type {
        int connector_type;
index d55c0c232e1d40c73520220d24a5ef2f5bc25488..f69b92535505b5ae1c899d6f9b08f76501851fa7 100644 (file)
@@ -207,6 +207,27 @@ static void atmel_hlcdc_crtc_enable(struct drm_crtc *c)
        crtc->enabled = true;
 }
 
+void atmel_hlcdc_crtc_suspend(struct drm_crtc *c)
+{
+       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+
+       if (crtc->enabled) {
+               atmel_hlcdc_crtc_disable(c);
+               /* save enable state for resume */
+               crtc->enabled = true;
+       }
+}
+
+void atmel_hlcdc_crtc_resume(struct drm_crtc *c)
+{
+       struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+
+       if (crtc->enabled) {
+               crtc->enabled = false;
+               atmel_hlcdc_crtc_enable(c);
+       }
+}
+
 static int atmel_hlcdc_crtc_atomic_check(struct drm_crtc *c,
                                         struct drm_crtc_state *s)
 {
index c4bb1f9f95c63382250e9f09a95b9a1cf2dd6216..60b0c13d7ff5cc6f4c338c9ed3d7f423d684c84e 100644 (file)
@@ -569,14 +569,8 @@ static int atmel_hlcdc_dc_drm_suspend(struct device *dev)
                return 0;
 
        drm_modeset_lock_all(drm_dev);
-       list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
-               struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
-               if (crtc->enabled) {
-                       crtc_funcs->disable(crtc);
-                       /* save enable state for resume */
-                       crtc->enabled = true;
-               }
-       }
+       list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head)
+               atmel_hlcdc_crtc_suspend(crtc);
        drm_modeset_unlock_all(drm_dev);
        return 0;
 }
@@ -590,13 +584,8 @@ static int atmel_hlcdc_dc_drm_resume(struct device *dev)
                return 0;
 
        drm_modeset_lock_all(drm_dev);
-       list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
-               struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
-               if (crtc->enabled) {
-                       crtc->enabled = false;
-                       crtc_funcs->enable(crtc);
-               }
-       }
+       list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head)
+               atmel_hlcdc_crtc_resume(crtc);
        drm_modeset_unlock_all(drm_dev);
        return 0;
 }
index 1ea9c2ccd8a74f0a1e4918a2a1a3f7127aa0adda..cf6b375bc38d1430c892ea2bf69cdf144047efd8 100644 (file)
@@ -155,6 +155,9 @@ void atmel_hlcdc_crtc_irq(struct drm_crtc *c);
 void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *crtc,
                                       struct drm_file *file);
 
+void atmel_hlcdc_crtc_suspend(struct drm_crtc *crtc);
+void atmel_hlcdc_crtc_resume(struct drm_crtc *crtc);
+
 int atmel_hlcdc_crtc_create(struct drm_device *dev);
 
 int atmel_hlcdc_create_outputs(struct drm_device *dev);
index 460389702d31cdca34a56b9e20c93f6ad4ad6f05..a39b0343c197dc8a6aea00aa244b80dae1fde232 100644 (file)
@@ -164,6 +164,7 @@ void bochs_hw_setmode(struct bochs_device *bochs,
 
        bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */
 
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE,      0);
        bochs_dispi_write(bochs, VBE_DISPI_INDEX_BPP,         bochs->bpp);
        bochs_dispi_write(bochs, VBE_DISPI_INDEX_XRES,        bochs->xres);
        bochs_dispi_write(bochs, VBE_DISPI_INDEX_YRES,        bochs->yres);
index f38bbcdf929bfc52efdb279212dacdb265d06fbf..acef3223772cb89911c18b2392123fed1bdc28ff 100644 (file)
@@ -11,3 +11,14 @@ config DRM_PTN3460
        select DRM_PANEL
        ---help---
          ptn3460 eDP-LVDS bridge chip driver.
+
+config DRM_PS8622
+       tristate "Parade eDP/LVDS bridge"
+       depends on DRM
+       depends on OF
+       select DRM_PANEL
+       select DRM_KMS_HELPER
+       select BACKLIGHT_LCD_SUPPORT
+       select BACKLIGHT_CLASS_DEVICE
+       ---help---
+         parade eDP-LVDS bridge chip driver.
index d8a8cfd12fbbb4d72c872359408ca617a17f295e..8dfebd984370e17cac7a76f03e96bac3e7c444a8 100644 (file)
@@ -1,4 +1,5 @@
 ccflags-y := -Iinclude/drm
 
+obj-$(CONFIG_DRM_PS8622) += ps8622.o
 obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
 obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
index cd6a70647e3224ba1b45e135b5f6e066a33a5358..49cafb61d29075530840a78766541ad4e9ceb478 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/hdmi.h>
+#include <linux/mutex.h>
 #include <linux/of_device.h>
 
 #include <drm/drm_of.h>
@@ -126,6 +127,7 @@ struct dw_hdmi {
        struct i2c_adapter *ddc;
        void __iomem *regs;
 
+       struct mutex audio_mutex;
        unsigned int sample_rate;
        int ratio;
 
@@ -177,26 +179,23 @@ static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
        hdmi_modb(hdmi, data << shift, mask, reg);
 }
 
-static void hdmi_set_clock_regenerator_n(struct dw_hdmi *hdmi,
-                                        unsigned int value)
+static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts,
+                          unsigned int n)
 {
-       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);
+       /* Must be set/cleared first */
+       hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
 
        /* nshift factor = 0 */
        hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
-}
-
-static void hdmi_regenerate_cts(struct dw_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);
+       hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
+       hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
+
+       hdmi_writeb(hdmi, (n >> 16) & 0x0f, HDMI_AUD_N3);
+       hdmi_writeb(hdmi, (n >> 8) & 0xff, HDMI_AUD_N2);
+       hdmi_writeb(hdmi, n & 0xff, HDMI_AUD_N1);
 }
 
 static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk,
@@ -355,18 +354,21 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
                __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);
+       hdmi_set_cts_n(hdmi, clk_cts, clk_n);
 }
 
 static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi)
 {
+       mutex_lock(&hdmi->audio_mutex);
        hdmi_set_clk_regenerator(hdmi, 74250000);
+       mutex_unlock(&hdmi->audio_mutex);
 }
 
 static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
 {
+       mutex_lock(&hdmi->audio_mutex);
        hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
+       mutex_unlock(&hdmi->audio_mutex);
 }
 
 /*
@@ -753,10 +755,10 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
 {
        unsigned res_idx, i;
        u8 val, msec;
-       const struct dw_hdmi_mpll_config *mpll_config =
-                                               hdmi->plat_data->mpll_cfg;
-       const struct dw_hdmi_curr_ctrl *curr_ctrl = hdmi->plat_data->cur_ctr;
-       const struct dw_hdmi_sym_term *sym_term =  hdmi->plat_data->sym_term;
+       const struct dw_hdmi_plat_data *plat_data = hdmi->plat_data;
+       const struct dw_hdmi_mpll_config *mpll_config = plat_data->mpll_cfg;
+       const struct dw_hdmi_curr_ctrl *curr_ctrl = plat_data->cur_ctr;
+       const struct dw_hdmi_phy_config *phy_config = plat_data->phy_config;
 
        if (prep)
                return -EINVAL;
@@ -827,18 +829,18 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
        hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);  /* PLLPHBYCTRL */
        hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
 
-       for (i = 0; sym_term[i].mpixelclock != (~0UL); i++)
+       for (i = 0; phy_config[i].mpixelclock != (~0UL); i++)
                if (hdmi->hdmi_data.video_mode.mpixelclock <=
-                   sym_term[i].mpixelclock)
+                   phy_config[i].mpixelclock)
                        break;
 
        /* RESISTANCE TERM 133Ohm Cfg */
-       hdmi_phy_i2c_write(hdmi, sym_term[i].term, 0x19);  /* TXTERM */
+       hdmi_phy_i2c_write(hdmi, phy_config[i].term, 0x19);  /* TXTERM */
        /* PREEMP Cgf 0.00 */
-       hdmi_phy_i2c_write(hdmi, sym_term[i].sym_ctr, 0x09);  /* CKSYMTXCTRL */
-
+       hdmi_phy_i2c_write(hdmi, phy_config[i].sym_ctr, 0x09); /* CKSYMTXCTRL */
        /* TX/CK LVL 10 */
-       hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E);  /* VLEVCTRL */
+       hdmi_phy_i2c_write(hdmi, phy_config[i].vlev_ctr, 0x0E); /* VLEVCTRL */
+
        /* REMOVE CLK TERM */
        hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);  /* CKCALCTRL */
 
@@ -1569,6 +1571,8 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
        hdmi->ratio = 100;
        hdmi->encoder = encoder;
 
+       mutex_init(&hdmi->audio_mutex);
+
        of_property_read_u32(np, "reg-io-width", &val);
 
        switch (val) {
diff --git a/drivers/gpu/drm/bridge/ps8622.c b/drivers/gpu/drm/bridge/ps8622.c
new file mode 100644 (file)
index 0000000..e895aa7
--- /dev/null
@@ -0,0 +1,684 @@
+/*
+ * Parade PS8622 eDP/LVDS bridge driver
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/backlight.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/pm.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_panel.h>
+
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+
+/* Brightness scale on the Parade chip */
+#define PS8622_MAX_BRIGHTNESS 0xff
+
+/* Timings taken from the version 1.7 datasheet for the PS8622/PS8625 */
+#define PS8622_POWER_RISE_T1_MIN_US 10
+#define PS8622_POWER_RISE_T1_MAX_US 10000
+#define PS8622_RST_HIGH_T2_MIN_US 3000
+#define PS8622_RST_HIGH_T2_MAX_US 30000
+#define PS8622_PWMO_END_T12_MS 200
+#define PS8622_POWER_FALL_T16_MAX_US 10000
+#define PS8622_POWER_OFF_T17_MS 500
+
+#if ((PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US) > \
+       (PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US))
+#error "T2.min + T1.max must be less than T2.max + T1.min"
+#endif
+
+struct ps8622_bridge {
+       struct drm_connector connector;
+       struct i2c_client *client;
+       struct drm_bridge bridge;
+       struct drm_panel *panel;
+       struct regulator *v12;
+       struct backlight_device *bl;
+
+       struct gpio_desc *gpio_slp;
+       struct gpio_desc *gpio_rst;
+
+       u32 max_lane_count;
+       u32 lane_count;
+
+       bool enabled;
+};
+
+static inline struct ps8622_bridge *
+               bridge_to_ps8622(struct drm_bridge *bridge)
+{
+       return container_of(bridge, struct ps8622_bridge, bridge);
+}
+
+static inline struct ps8622_bridge *
+               connector_to_ps8622(struct drm_connector *connector)
+{
+       return container_of(connector, struct ps8622_bridge, connector);
+}
+
+static int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val)
+{
+       int ret;
+       struct i2c_adapter *adap = client->adapter;
+       struct i2c_msg msg;
+       u8 data[] = {reg, val};
+
+       msg.addr = client->addr + page;
+       msg.flags = 0;
+       msg.len = sizeof(data);
+       msg.buf = data;
+
+       ret = i2c_transfer(adap, &msg, 1);
+       if (ret != 1)
+               pr_warn("PS8622 I2C write (0x%02x,0x%02x,0x%02x) failed: %d\n",
+                       client->addr + page, reg, val, ret);
+       return !(ret == 1);
+}
+
+static int ps8622_send_config(struct ps8622_bridge *ps8622)
+{
+       struct i2c_client *cl = ps8622->client;
+       int err = 0;
+
+       /* HPD low */
+       err = ps8622_set(cl, 0x02, 0xa1, 0x01);
+       if (err)
+               goto error;
+
+       /* SW setting: [1:0] SW output 1.2V voltage is lower to 96% */
+       err = ps8622_set(cl, 0x04, 0x14, 0x01);
+       if (err)
+               goto error;
+
+       /* RCO SS setting: [5:4] = b01 0.5%, b10 1%, b11 1.5% */
+       err = ps8622_set(cl, 0x04, 0xe3, 0x20);
+       if (err)
+               goto error;
+
+       /* [7] RCO SS enable */
+       err = ps8622_set(cl, 0x04, 0xe2, 0x80);
+       if (err)
+               goto error;
+
+       /* RPHY Setting
+        * [3:2] CDR tune wait cycle before measure for fine tune
+        * b00: 1us b01: 0.5us b10:2us, b11: 4us
+        */
+       err = ps8622_set(cl, 0x04, 0x8a, 0x0c);
+       if (err)
+               goto error;
+
+       /* [3] RFD always on */
+       err = ps8622_set(cl, 0x04, 0x89, 0x08);
+       if (err)
+               goto error;
+
+       /* CTN lock in/out: 20000ppm/80000ppm. Lock out 2 times. */
+       err = ps8622_set(cl, 0x04, 0x71, 0x2d);
+       if (err)
+               goto error;
+
+       /* 2.7G CDR settings: NOF=40LSB for HBR CDR  setting */
+       err = ps8622_set(cl, 0x04, 0x7d, 0x07);
+       if (err)
+               goto error;
+
+       /* [1:0] Fmin=+4bands */
+       err = ps8622_set(cl, 0x04, 0x7b, 0x00);
+       if (err)
+               goto error;
+
+       /* [7:5] DCO_FTRNG=+-40% */
+       err = ps8622_set(cl, 0x04, 0x7a, 0xfd);
+       if (err)
+               goto error;
+
+       /* 1.62G CDR settings: [5:2]NOF=64LSB [1:0]DCO scale is 2/5 */
+       err = ps8622_set(cl, 0x04, 0xc0, 0x12);
+       if (err)
+               goto error;
+
+       /* Gitune=-37% */
+       err = ps8622_set(cl, 0x04, 0xc1, 0x92);
+       if (err)
+               goto error;
+
+       /* Fbstep=100% */
+       err = ps8622_set(cl, 0x04, 0xc2, 0x1c);
+       if (err)
+               goto error;
+
+       /* [7] LOS signal disable */
+       err = ps8622_set(cl, 0x04, 0x32, 0x80);
+       if (err)
+               goto error;
+
+       /* RPIO Setting: [7:4] LVDS driver bias current : 75% (250mV swing) */
+       err = ps8622_set(cl, 0x04, 0x00, 0xb0);
+       if (err)
+               goto error;
+
+       /* [7:6] Right-bar GPIO output strength is 8mA */
+       err = ps8622_set(cl, 0x04, 0x15, 0x40);
+       if (err)
+               goto error;
+
+       /* EQ Training State Machine Setting, RCO calibration start */
+       err = ps8622_set(cl, 0x04, 0x54, 0x10);
+       if (err)
+               goto error;
+
+       /* Logic, needs more than 10 I2C command */
+       /* [4:0] MAX_LANE_COUNT set to max supported lanes */
+       err = ps8622_set(cl, 0x01, 0x02, 0x80 | ps8622->max_lane_count);
+       if (err)
+               goto error;
+
+       /* [4:0] LANE_COUNT_SET set to chosen lane count */
+       err = ps8622_set(cl, 0x01, 0x21, 0x80 | ps8622->lane_count);
+       if (err)
+               goto error;
+
+       err = ps8622_set(cl, 0x00, 0x52, 0x20);
+       if (err)
+               goto error;
+
+       /* HPD CP toggle enable */
+       err = ps8622_set(cl, 0x00, 0xf1, 0x03);
+       if (err)
+               goto error;
+
+       err = ps8622_set(cl, 0x00, 0x62, 0x41);
+       if (err)
+               goto error;
+
+       /* Counter number, add 1ms counter delay */
+       err = ps8622_set(cl, 0x00, 0xf6, 0x01);
+       if (err)
+               goto error;
+
+       /* [6]PWM function control by DPCD0040f[7], default is PWM block */
+       err = ps8622_set(cl, 0x00, 0x77, 0x06);
+       if (err)
+               goto error;
+
+       /* 04h Adjust VTotal toleranceto fix the 30Hz no display issue */
+       err = ps8622_set(cl, 0x00, 0x4c, 0x04);
+       if (err)
+               goto error;
+
+       /* DPCD00400='h00, Parade OUI ='h001cf8 */
+       err = ps8622_set(cl, 0x01, 0xc0, 0x00);
+       if (err)
+               goto error;
+
+       /* DPCD00401='h1c */
+       err = ps8622_set(cl, 0x01, 0xc1, 0x1c);
+       if (err)
+               goto error;
+
+       /* DPCD00402='hf8 */
+       err = ps8622_set(cl, 0x01, 0xc2, 0xf8);
+       if (err)
+               goto error;
+
+       /* DPCD403~408 = ASCII code, D2SLV5='h4432534c5635 */
+       err = ps8622_set(cl, 0x01, 0xc3, 0x44);
+       if (err)
+               goto error;
+
+       /* DPCD404 */
+       err = ps8622_set(cl, 0x01, 0xc4, 0x32);
+       if (err)
+               goto error;
+
+       /* DPCD405 */
+       err = ps8622_set(cl, 0x01, 0xc5, 0x53);
+       if (err)
+               goto error;
+
+       /* DPCD406 */
+       err = ps8622_set(cl, 0x01, 0xc6, 0x4c);
+       if (err)
+               goto error;
+
+       /* DPCD407 */
+       err = ps8622_set(cl, 0x01, 0xc7, 0x56);
+       if (err)
+               goto error;
+
+       /* DPCD408 */
+       err = ps8622_set(cl, 0x01, 0xc8, 0x35);
+       if (err)
+               goto error;
+
+       /* DPCD40A, Initial Code major revision '01' */
+       err = ps8622_set(cl, 0x01, 0xca, 0x01);
+       if (err)
+               goto error;
+
+       /* DPCD40B, Initial Code minor revision '05' */
+       err = ps8622_set(cl, 0x01, 0xcb, 0x05);
+       if (err)
+               goto error;
+
+
+       if (ps8622->bl) {
+               /* DPCD720, internal PWM */
+               err = ps8622_set(cl, 0x01, 0xa5, 0xa0);
+               if (err)
+                       goto error;
+
+               /* FFh for 100% brightness, 0h for 0% brightness */
+               err = ps8622_set(cl, 0x01, 0xa7,
+                               ps8622->bl->props.brightness);
+               if (err)
+                       goto error;
+       } else {
+               /* DPCD720, external PWM */
+               err = ps8622_set(cl, 0x01, 0xa5, 0x80);
+               if (err)
+                       goto error;
+       }
+
+       /* Set LVDS output as 6bit-VESA mapping, single LVDS channel */
+       err = ps8622_set(cl, 0x01, 0xcc, 0x13);
+       if (err)
+               goto error;
+
+       /* Enable SSC set by register */
+       err = ps8622_set(cl, 0x02, 0xb1, 0x20);
+       if (err)
+               goto error;
+
+       /* Set SSC enabled and +/-1% central spreading */
+       err = ps8622_set(cl, 0x04, 0x10, 0x16);
+       if (err)
+               goto error;
+
+       /* Logic end */
+       /* MPU Clock source: LC => RCO */
+       err = ps8622_set(cl, 0x04, 0x59, 0x60);
+       if (err)
+               goto error;
+
+       /* LC -> RCO */
+       err = ps8622_set(cl, 0x04, 0x54, 0x14);
+       if (err)
+               goto error;
+
+       /* HPD high */
+       err = ps8622_set(cl, 0x02, 0xa1, 0x91);
+
+error:
+       return err ? -EIO : 0;
+}
+
+static int ps8622_backlight_update(struct backlight_device *bl)
+{
+       struct ps8622_bridge *ps8622 = dev_get_drvdata(&bl->dev);
+       int ret, brightness = bl->props.brightness;
+
+       if (bl->props.power != FB_BLANK_UNBLANK ||
+           bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
+               brightness = 0;
+
+       if (!ps8622->enabled)
+               return -EINVAL;
+
+       ret = ps8622_set(ps8622->client, 0x01, 0xa7, brightness);
+
+       return ret;
+}
+
+static const struct backlight_ops ps8622_backlight_ops = {
+       .update_status  = ps8622_backlight_update,
+};
+
+static void ps8622_pre_enable(struct drm_bridge *bridge)
+{
+       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+       int ret;
+
+       if (ps8622->enabled)
+               return;
+
+       gpiod_set_value(ps8622->gpio_rst, 0);
+
+       if (ps8622->v12) {
+               ret = regulator_enable(ps8622->v12);
+               if (ret)
+                       DRM_ERROR("fails to enable ps8622->v12");
+       }
+
+       if (drm_panel_prepare(ps8622->panel)) {
+               DRM_ERROR("failed to prepare panel\n");
+               return;
+       }
+
+       gpiod_set_value(ps8622->gpio_slp, 1);
+
+       /*
+        * T1 is the range of time that it takes for the power to rise after we
+        * enable the lcd/ps8622 fet. T2 is the range of time in which the
+        * data sheet specifies we should deassert the reset pin.
+        *
+        * If it takes T1.max for the power to rise, we need to wait atleast
+        * T2.min before deasserting the reset pin. If it takes T1.min for the
+        * power to rise, we need to wait at most T2.max before deasserting the
+        * reset pin.
+        */
+       usleep_range(PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US,
+                    PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US);
+
+       gpiod_set_value(ps8622->gpio_rst, 1);
+
+       /* wait 20ms after RST high */
+       usleep_range(20000, 30000);
+
+       ret = ps8622_send_config(ps8622);
+       if (ret) {
+               DRM_ERROR("Failed to send config to bridge (%d)\n", ret);
+               return;
+       }
+
+       ps8622->enabled = true;
+}
+
+static void ps8622_enable(struct drm_bridge *bridge)
+{
+       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+
+       if (drm_panel_enable(ps8622->panel)) {
+               DRM_ERROR("failed to enable panel\n");
+               return;
+       }
+}
+
+static void ps8622_disable(struct drm_bridge *bridge)
+{
+       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+
+       if (drm_panel_disable(ps8622->panel)) {
+               DRM_ERROR("failed to disable panel\n");
+               return;
+       }
+       msleep(PS8622_PWMO_END_T12_MS);
+}
+
+static void ps8622_post_disable(struct drm_bridge *bridge)
+{
+       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+
+       if (!ps8622->enabled)
+               return;
+
+       ps8622->enabled = false;
+
+       /*
+        * This doesn't matter if the regulators are turned off, but something
+        * else might keep them on. In that case, we want to assert the slp gpio
+        * to lower power.
+        */
+       gpiod_set_value(ps8622->gpio_slp, 0);
+
+       if (drm_panel_unprepare(ps8622->panel)) {
+               DRM_ERROR("failed to unprepare panel\n");
+               return;
+       }
+
+       if (ps8622->v12)
+               regulator_disable(ps8622->v12);
+
+       /*
+        * Sleep for at least the amount of time that it takes the power rail to
+        * fall to prevent asserting the rst gpio from doing anything.
+        */
+       usleep_range(PS8622_POWER_FALL_T16_MAX_US,
+                    2 * PS8622_POWER_FALL_T16_MAX_US);
+       gpiod_set_value(ps8622->gpio_rst, 0);
+
+       msleep(PS8622_POWER_OFF_T17_MS);
+}
+
+static int ps8622_get_modes(struct drm_connector *connector)
+{
+       struct ps8622_bridge *ps8622;
+
+       ps8622 = connector_to_ps8622(connector);
+
+       return drm_panel_get_modes(ps8622->panel);
+}
+
+static struct drm_encoder *ps8622_best_encoder(struct drm_connector *connector)
+{
+       struct ps8622_bridge *ps8622;
+
+       ps8622 = connector_to_ps8622(connector);
+
+       return ps8622->bridge.encoder;
+}
+
+static const struct drm_connector_helper_funcs ps8622_connector_helper_funcs = {
+       .get_modes = ps8622_get_modes,
+       .best_encoder = ps8622_best_encoder,
+};
+
+static enum drm_connector_status ps8622_detect(struct drm_connector *connector,
+                                                               bool force)
+{
+       return connector_status_connected;
+}
+
+static void ps8622_connector_destroy(struct drm_connector *connector)
+{
+       drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs ps8622_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .detect = ps8622_detect,
+       .destroy = ps8622_connector_destroy,
+};
+
+static int ps8622_attach(struct drm_bridge *bridge)
+{
+       struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
+       int ret;
+
+       if (!bridge->encoder) {
+               DRM_ERROR("Parent encoder object not found");
+               return -ENODEV;
+       }
+
+       ps8622->connector.polled = DRM_CONNECTOR_POLL_HPD;
+       ret = drm_connector_init(bridge->dev, &ps8622->connector,
+                       &ps8622_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
+       if (ret) {
+               DRM_ERROR("Failed to initialize connector with drm\n");
+               return ret;
+       }
+       drm_connector_helper_add(&ps8622->connector,
+                                       &ps8622_connector_helper_funcs);
+       drm_connector_register(&ps8622->connector);
+       drm_mode_connector_attach_encoder(&ps8622->connector,
+                                                       bridge->encoder);
+
+       if (ps8622->panel)
+               drm_panel_attach(ps8622->panel, &ps8622->connector);
+
+       drm_helper_hpd_irq_event(ps8622->connector.dev);
+
+       return ret;
+}
+
+static const struct drm_bridge_funcs ps8622_bridge_funcs = {
+       .pre_enable = ps8622_pre_enable,
+       .enable = ps8622_enable,
+       .disable = ps8622_disable,
+       .post_disable = ps8622_post_disable,
+       .attach = ps8622_attach,
+};
+
+static const struct of_device_id ps8622_devices[] = {
+       {.compatible = "parade,ps8622",},
+       {.compatible = "parade,ps8625",},
+       {}
+};
+MODULE_DEVICE_TABLE(of, ps8622_devices);
+
+static int ps8622_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct device_node *endpoint, *panel_node;
+       struct ps8622_bridge *ps8622;
+       int ret;
+
+       ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL);
+       if (!ps8622)
+               return -ENOMEM;
+
+       endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+       if (endpoint) {
+               panel_node = of_graph_get_remote_port_parent(endpoint);
+               if (panel_node) {
+                       ps8622->panel = of_drm_find_panel(panel_node);
+                       of_node_put(panel_node);
+                       if (!ps8622->panel)
+                               return -EPROBE_DEFER;
+               }
+       }
+
+       ps8622->client = client;
+
+       ps8622->v12 = devm_regulator_get(dev, "vdd12");
+       if (IS_ERR(ps8622->v12)) {
+               dev_info(dev, "no 1.2v regulator found for PS8622\n");
+               ps8622->v12 = NULL;
+       }
+
+       ps8622->gpio_slp = devm_gpiod_get(dev, "sleep");
+       if (IS_ERR(ps8622->gpio_slp)) {
+               ret = PTR_ERR(ps8622->gpio_slp);
+               dev_err(dev, "cannot get gpio_slp %d\n", ret);
+               return ret;
+       }
+       ret = gpiod_direction_output(ps8622->gpio_slp, 1);
+       if (ret) {
+               dev_err(dev, "cannot configure gpio_slp\n");
+               return ret;
+       }
+
+       ps8622->gpio_rst = devm_gpiod_get(dev, "reset");
+       if (IS_ERR(ps8622->gpio_rst)) {
+               ret = PTR_ERR(ps8622->gpio_rst);
+               dev_err(dev, "cannot get gpio_rst %d\n", ret);
+               return ret;
+       }
+       /*
+        * Assert the reset pin high to avoid the bridge being
+        * initialized prematurely
+        */
+       ret = gpiod_direction_output(ps8622->gpio_rst, 1);
+       if (ret) {
+               dev_err(dev, "cannot configure gpio_rst\n");
+               return ret;
+       }
+
+       ps8622->max_lane_count = id->driver_data;
+
+       if (of_property_read_u32(dev->of_node, "lane-count",
+                                               &ps8622->lane_count)) {
+               ps8622->lane_count = ps8622->max_lane_count;
+       } else if (ps8622->lane_count > ps8622->max_lane_count) {
+               dev_info(dev, "lane-count property is too high,"
+                                               "using max_lane_count\n");
+               ps8622->lane_count = ps8622->max_lane_count;
+       }
+
+       if (!of_find_property(dev->of_node, "use-external-pwm", NULL)) {
+               ps8622->bl = backlight_device_register("ps8622-backlight",
+                               dev, ps8622, &ps8622_backlight_ops,
+                               NULL);
+               if (IS_ERR(ps8622->bl)) {
+                       DRM_ERROR("failed to register backlight\n");
+                       ret = PTR_ERR(ps8622->bl);
+                       ps8622->bl = NULL;
+                       return ret;
+               }
+               ps8622->bl->props.max_brightness = PS8622_MAX_BRIGHTNESS;
+               ps8622->bl->props.brightness = PS8622_MAX_BRIGHTNESS;
+       }
+
+       ps8622->bridge.funcs = &ps8622_bridge_funcs;
+       ps8622->bridge.of_node = dev->of_node;
+       ret = drm_bridge_add(&ps8622->bridge);
+       if (ret) {
+               DRM_ERROR("Failed to add bridge\n");
+               return ret;
+       }
+
+       i2c_set_clientdata(client, ps8622);
+
+       return 0;
+}
+
+static int ps8622_remove(struct i2c_client *client)
+{
+       struct ps8622_bridge *ps8622 = i2c_get_clientdata(client);
+
+       if (ps8622->bl)
+               backlight_device_unregister(ps8622->bl);
+
+       drm_bridge_remove(&ps8622->bridge);
+
+       return 0;
+}
+
+static const struct i2c_device_id ps8622_i2c_table[] = {
+       /* Device type, max_lane_count */
+       {"ps8622", 1},
+       {"ps8625", 2},
+       {},
+};
+MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table);
+
+static struct i2c_driver ps8622_driver = {
+       .id_table       = ps8622_i2c_table,
+       .probe          = ps8622_probe,
+       .remove         = ps8622_remove,
+       .driver         = {
+               .name   = "ps8622",
+               .owner  = THIS_MODULE,
+               .of_match_table = ps8622_devices,
+       },
+};
+module_i2c_driver(ps8622_driver);
+
+MODULE_AUTHOR("Vincent Palatin <vpalatin@chromium.org>");
+MODULE_DESCRIPTION("Parade ps8622/ps8625 eDP-LVDS converter driver");
+MODULE_LICENSE("GPL v2");
index 826833e396f0930886e438edc1ef97f652ef2a77..9d2f053382e1889acbd8be4048403292c8615884 100644 (file)
@@ -265,7 +265,7 @@ static struct drm_connector_funcs ptn3460_connector_funcs = {
        .destroy = ptn3460_connector_destroy,
 };
 
-int ptn3460_bridge_attach(struct drm_bridge *bridge)
+static int ptn3460_bridge_attach(struct drm_bridge *bridge)
 {
        struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
        int ret;
index a6caaae40b9ebc25e26b80e7071f240431b3f31b..6e3b78ee7d16b824e67421446b407d064fd77be8 100644 (file)
@@ -134,6 +134,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
 
                connector->funcs->atomic_destroy_state(connector,
                                                       state->connector_states[i]);
+               state->connectors[i] = NULL;
                state->connector_states[i] = NULL;
        }
 
@@ -145,6 +146,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
 
                crtc->funcs->atomic_destroy_state(crtc,
                                                  state->crtc_states[i]);
+               state->crtcs[i] = NULL;
                state->crtc_states[i] = NULL;
        }
 
@@ -156,6 +158,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
 
                plane->funcs->atomic_destroy_state(plane,
                                                   state->plane_states[i]);
+               state->planes[i] = NULL;
                state->plane_states[i] = NULL;
        }
 }
@@ -170,6 +173,9 @@ EXPORT_SYMBOL(drm_atomic_state_clear);
  */
 void drm_atomic_state_free(struct drm_atomic_state *state)
 {
+       if (!state)
+               return;
+
        drm_atomic_state_clear(state);
 
        DRM_DEBUG_ATOMIC("Freeing atomic state %p\n", state);
@@ -248,11 +254,14 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
        struct drm_mode_config *config = &dev->mode_config;
 
        /* FIXME: Mode prop is missing, which also controls ->enable. */
-       if (property == config->prop_active) {
+       if (property == config->prop_active)
                state->active = val;
-       else if (crtc->funcs->atomic_set_property)
+       else if (crtc->funcs->atomic_set_property)
                return crtc->funcs->atomic_set_property(crtc, state, property, val);
-       return -EINVAL;
+       else
+               return -EINVAL;
+
+       return 0;
 }
 EXPORT_SYMBOL(drm_atomic_crtc_set_property);
 
@@ -266,9 +275,17 @@ int drm_atomic_crtc_get_property(struct drm_crtc *crtc,
                const struct drm_crtc_state *state,
                struct drm_property *property, uint64_t *val)
 {
-       if (crtc->funcs->atomic_get_property)
+       struct drm_device *dev = crtc->dev;
+       struct drm_mode_config *config = &dev->mode_config;
+
+       if (property == config->prop_active)
+               *val = state->active;
+       else if (crtc->funcs->atomic_get_property)
                return crtc->funcs->atomic_get_property(crtc, state, property, val);
-       return -EINVAL;
+       else
+               return -EINVAL;
+
+       return 0;
 }
 
 /**
@@ -763,7 +780,7 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
 EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
 
 /**
- * drm_atomic_set_fb_for_plane - set crtc for plane
+ * drm_atomic_set_fb_for_plane - set framebuffer for plane
  * @plane_state: atomic state object for the plane
  * @fb: fb to use for the plane
  *
@@ -892,14 +909,13 @@ int
 drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
                               struct drm_crtc *crtc)
 {
-       int i, num_connected_connectors = 0;
-
-       for (i = 0; i < state->num_connector; i++) {
-               struct drm_connector_state *conn_state;
+       struct drm_connector *connector;
+       struct drm_connector_state *conn_state;
 
-               conn_state = state->connector_states[i];
+       int i, num_connected_connectors = 0;
 
-               if (conn_state && conn_state->crtc == crtc)
+       for_each_connector_in_state(state, connector, conn_state, i) {
+               if (conn_state->crtc == crtc)
                        num_connected_connectors++;
        }
 
@@ -916,7 +932,7 @@ EXPORT_SYMBOL(drm_atomic_connectors_for_crtc);
  *
  * This function should be used by legacy entry points which don't understand
  * -EDEADLK semantics. For simplicity this one will grab all modeset locks after
- *  the slowpath completed.
+ * the slowpath completed.
  */
 void drm_atomic_legacy_backoff(struct drm_atomic_state *state)
 {
@@ -951,19 +967,16 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
 {
        struct drm_device *dev = state->dev;
        struct drm_mode_config *config = &dev->mode_config;
-       int nplanes = config->num_total_plane;
-       int ncrtcs = config->num_crtc;
+       struct drm_plane *plane;
+       struct drm_plane_state *plane_state;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *crtc_state;
        int i, ret = 0;
 
        DRM_DEBUG_ATOMIC("checking %p\n", state);
 
-       for (i = 0; i < nplanes; i++) {
-               struct drm_plane *plane = state->planes[i];
-
-               if (!plane)
-                       continue;
-
-               ret = drm_atomic_plane_check(plane, state->plane_states[i]);
+       for_each_plane_in_state(state, plane, plane_state, i) {
+               ret = drm_atomic_plane_check(plane, plane_state);
                if (ret) {
                        DRM_DEBUG_ATOMIC("[PLANE:%d] atomic core check failed\n",
                                         plane->base.id);
@@ -971,13 +984,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
                }
        }
 
-       for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc *crtc = state->crtcs[i];
-
-               if (!crtc)
-                       continue;
-
-               ret = drm_atomic_crtc_check(crtc, state->crtc_states[i]);
+       for_each_crtc_in_state(state, crtc, crtc_state, i) {
+               ret = drm_atomic_crtc_check(crtc, crtc_state);
                if (ret) {
                        DRM_DEBUG_ATOMIC("[CRTC:%d] atomic core check failed\n",
                                         crtc->base.id);
@@ -989,13 +997,7 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
                ret = config->funcs->atomic_check(state->dev, state);
 
        if (!state->allow_modeset) {
-               for (i = 0; i < ncrtcs; i++) {
-                       struct drm_crtc *crtc = state->crtcs[i];
-                       struct drm_crtc_state *crtc_state = state->crtc_states[i];
-
-                       if (!crtc)
-                               continue;
-
+               for_each_crtc_in_state(state, crtc, crtc_state, i) {
                        if (crtc_state->mode_changed ||
                            crtc_state->active_changed) {
                                DRM_DEBUG_ATOMIC("[CRTC:%d] requires full modeset\n",
@@ -1193,6 +1195,8 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
        struct drm_atomic_state *state;
        struct drm_modeset_acquire_ctx ctx;
        struct drm_plane *plane;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *crtc_state;
        unsigned plane_mask = 0;
        int ret = 0;
        unsigned int i, j;
@@ -1296,15 +1300,9 @@ retry:
        }
 
        if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
-               int ncrtcs = dev->mode_config.num_crtc;
-
-               for (i = 0; i < ncrtcs; i++) {
-                       struct drm_crtc_state *crtc_state = state->crtc_states[i];
+               for_each_crtc_in_state(state, crtc, crtc_state, i) {
                        struct drm_pending_vblank_event *e;
 
-                       if (!crtc_state)
-                               continue;
-
                        e = create_vblank_event(dev, file_priv, arg->user_data);
                        if (!e) {
                                ret = -ENOMEM;
@@ -1356,14 +1354,7 @@ fail:
                goto backoff;
 
        if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
-               int ncrtcs = dev->mode_config.num_crtc;
-
-               for (i = 0; i < ncrtcs; i++) {
-                       struct drm_crtc_state *crtc_state = state->crtc_states[i];
-
-                       if (!crtc_state)
-                               continue;
-
+               for_each_crtc_in_state(state, crtc, crtc_state, i) {
                        destroy_vblank_event(dev, file_priv, crtc_state->event);
                        crtc_state->event = NULL;
                }
index a7458813af2b8b7dcf81ccca746f0e8ae6d60634..1d2ca52530d5f3148fec55d72d22c79f2eaa8949 100644 (file)
@@ -151,7 +151,7 @@ steal_encoder(struct drm_atomic_state *state,
 static int
 update_connector_routing(struct drm_atomic_state *state, int conn_idx)
 {
-       struct drm_connector_helper_funcs *funcs;
+       const struct drm_connector_helper_funcs *funcs;
        struct drm_encoder *new_encoder;
        struct drm_crtc *encoder_crtc;
        struct drm_connector *connector;
@@ -248,30 +248,24 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
 static int
 mode_fixup(struct drm_atomic_state *state)
 {
-       int ncrtcs = state->dev->mode_config.num_crtc;
+       struct drm_crtc *crtc;
        struct drm_crtc_state *crtc_state;
+       struct drm_connector *connector;
        struct drm_connector_state *conn_state;
        int i;
        bool ret;
 
-       for (i = 0; i < ncrtcs; i++) {
-               crtc_state = state->crtc_states[i];
-
-               if (!crtc_state || !crtc_state->mode_changed)
+       for_each_crtc_in_state(state, crtc, crtc_state, i) {
+               if (!crtc_state->mode_changed)
                        continue;
 
                drm_mode_copy(&crtc_state->adjusted_mode, &crtc_state->mode);
        }
 
-       for (i = 0; i < state->num_connector; i++) {
-               struct drm_encoder_helper_funcs *funcs;
+       for_each_connector_in_state(state, connector, conn_state, i) {
+               const struct drm_encoder_helper_funcs *funcs;
                struct drm_encoder *encoder;
 
-               conn_state = state->connector_states[i];
-
-               if (!conn_state)
-                       continue;
-
                WARN_ON(!!conn_state->best_encoder != !!conn_state->crtc);
 
                if (!conn_state->crtc || !conn_state->best_encoder)
@@ -316,14 +310,10 @@ mode_fixup(struct drm_atomic_state *state)
                }
        }
 
-       for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
-               struct drm_crtc *crtc;
+       for_each_crtc_in_state(state, crtc, crtc_state, i) {
+               const struct drm_crtc_helper_funcs *funcs;
 
-               crtc_state = state->crtc_states[i];
-               crtc = state->crtcs[i];
-
-               if (!crtc_state || !crtc_state->mode_changed)
+               if (!crtc_state->mode_changed)
                        continue;
 
                funcs = crtc->helper_private;
@@ -346,7 +336,7 @@ needs_modeset(struct drm_crtc_state *state)
 }
 
 /**
- * drm_atomic_helper_check - validate state object for modeset changes
+ * drm_atomic_helper_check_modeset - validate state object for modeset changes
  * @dev: DRM device
  * @state: the driver state object
  *
@@ -371,18 +361,13 @@ int
 drm_atomic_helper_check_modeset(struct drm_device *dev,
                                struct drm_atomic_state *state)
 {
-       int ncrtcs = dev->mode_config.num_crtc;
        struct drm_crtc *crtc;
        struct drm_crtc_state *crtc_state;
+       struct drm_connector *connector;
+       struct drm_connector_state *connector_state;
        int i, ret;
 
-       for (i = 0; i < ncrtcs; i++) {
-               crtc = state->crtcs[i];
-               crtc_state = state->crtc_states[i];
-
-               if (!crtc)
-                       continue;
-
+       for_each_crtc_in_state(state, crtc, crtc_state, i) {
                if (!drm_mode_equal(&crtc->state->mode, &crtc_state->mode)) {
                        DRM_DEBUG_ATOMIC("[CRTC:%d] mode changed\n",
                                         crtc->base.id);
@@ -396,7 +381,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
                }
        }
 
-       for (i = 0; i < state->num_connector; i++) {
+       for_each_connector_in_state(state, connector, connector_state, i) {
                /*
                 * This only sets crtc->mode_changed for routing changes,
                 * drivers must set crtc->mode_changed themselves when connector
@@ -413,15 +398,9 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
         * configuration. This must be done before calling mode_fixup in case a
         * crtc only changed its mode but has the same set of connectors.
         */
-       for (i = 0; i < ncrtcs; i++) {
+       for_each_crtc_in_state(state, crtc, crtc_state, i) {
                int num_connectors;
 
-               crtc = state->crtcs[i];
-               crtc_state = state->crtc_states[i];
-
-               if (!crtc)
-                       continue;
-
                /*
                 * We must set ->active_changed after walking connectors for
                 * otherwise an update that only changes active would result in
@@ -461,7 +440,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
 EXPORT_SYMBOL(drm_atomic_helper_check_modeset);
 
 /**
- * drm_atomic_helper_check - validate state object for modeset changes
+ * drm_atomic_helper_check_planes - validate state object for planes changes
  * @dev: DRM device
  * @state: the driver state object
  *
@@ -476,17 +455,14 @@ int
 drm_atomic_helper_check_planes(struct drm_device *dev,
                               struct drm_atomic_state *state)
 {
-       int nplanes = dev->mode_config.num_total_plane;
-       int ncrtcs = dev->mode_config.num_crtc;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *crtc_state;
+       struct drm_plane *plane;
+       struct drm_plane_state *plane_state;
        int i, ret = 0;
 
-       for (i = 0; i < nplanes; i++) {
-               struct drm_plane_helper_funcs *funcs;
-               struct drm_plane *plane = state->planes[i];
-               struct drm_plane_state *plane_state = state->plane_states[i];
-
-               if (!plane)
-                       continue;
+       for_each_plane_in_state(state, plane, plane_state, i) {
+               const struct drm_plane_helper_funcs *funcs;
 
                funcs = plane->helper_private;
 
@@ -503,12 +479,8 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
                }
        }
 
-       for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
-               struct drm_crtc *crtc = state->crtcs[i];
-
-               if (!crtc)
-                       continue;
+       for_each_crtc_in_state(state, crtc, crtc_state, i) {
+               const struct drm_crtc_helper_funcs *funcs;
 
                funcs = crtc->helper_private;
 
@@ -567,27 +539,26 @@ EXPORT_SYMBOL(drm_atomic_helper_check);
 static void
 disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 {
-       int ncrtcs = old_state->dev->mode_config.num_crtc;
+       struct drm_connector *connector;
+       struct drm_connector_state *old_conn_state;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *old_crtc_state;
        int 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;
+       for_each_connector_in_state(old_state, connector, old_conn_state, i) {
+               const struct drm_encoder_helper_funcs *funcs;
                struct drm_encoder *encoder;
                struct drm_crtc_state *old_crtc_state;
 
-               old_conn_state = old_state->connector_states[i];
-               connector = old_state->connectors[i];
-
                /* Shut down everything that's in the changeset and currently
                 * still on. So need to check the old, saved state. */
-               if (!old_conn_state || !old_conn_state->crtc)
+               if (!old_conn_state->crtc)
                        continue;
 
                old_crtc_state = old_state->crtc_states[drm_crtc_index(old_conn_state->crtc)];
 
-               if (!old_crtc_state->active)
+               if (!old_crtc_state->active ||
+                   !needs_modeset(old_conn_state->crtc->state))
                        continue;
 
                encoder = old_conn_state->best_encoder;
@@ -605,7 +576,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 
                /*
                 * Each encoder has at most one connector (since we always steal
-                * it away), so we won't call call disable hooks twice.
+                * it away), so we won't call disable hooks twice.
                 */
                if (encoder->bridge)
                        encoder->bridge->funcs->disable(encoder->bridge);
@@ -622,16 +593,11 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
                        encoder->bridge->funcs->post_disable(encoder->bridge);
        }
 
-       for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
-               struct drm_crtc *crtc;
-               struct drm_crtc_state *old_crtc_state;
-
-               crtc = old_state->crtcs[i];
-               old_crtc_state = old_state->crtc_states[i];
+       for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
+               const struct drm_crtc_helper_funcs *funcs;
 
                /* Shut down everything that needs a full modeset. */
-               if (!crtc || !needs_modeset(crtc->state))
+               if (!needs_modeset(crtc->state))
                        continue;
 
                if (!old_crtc_state->active)
@@ -656,16 +622,15 @@ 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 ncrtcs = old_state->dev->mode_config.num_crtc;
+       struct drm_connector *connector;
+       struct drm_connector_state *old_conn_state;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *old_crtc_state;
        int i;
 
        /* clear out existing links */
-       for (i = 0; i < old_state->num_connector; i++) {
-               struct drm_connector *connector;
-
-               connector = old_state->connectors[i];
-
-               if (!connector || !connector->encoder)
+       for_each_connector_in_state(old_state, connector, old_conn_state, i) {
+               if (!connector->encoder)
                        continue;
 
                WARN_ON(!connector->encoder->crtc);
@@ -675,12 +640,8 @@ set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state)
        }
 
        /* set new links */
-       for (i = 0; i < old_state->num_connector; i++) {
-               struct drm_connector *connector;
-
-               connector = old_state->connectors[i];
-
-               if (!connector || !connector->state->crtc)
+       for_each_connector_in_state(old_state, connector, old_conn_state, i) {
+               if (!connector->state->crtc)
                        continue;
 
                if (WARN_ON(!connector->state->best_encoder))
@@ -691,14 +652,7 @@ set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state)
        }
 
        /* set legacy state in the crtc structure */
-       for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc *crtc;
-
-               crtc = old_state->crtcs[i];
-
-               if (!crtc)
-                       continue;
-
+       for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
                crtc->mode = crtc->state->mode;
                crtc->enabled = crtc->state->enable;
                crtc->x = crtc->primary->state->src_x >> 16;
@@ -709,16 +663,16 @@ set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state)
 static void
 crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
 {
-       int ncrtcs = old_state->dev->mode_config.num_crtc;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *old_crtc_state;
+       struct drm_connector *connector;
+       struct drm_connector_state *old_conn_state;
        int i;
 
-       for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
-               struct drm_crtc *crtc;
+       for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
+               const struct drm_crtc_helper_funcs *funcs;
 
-               crtc = old_state->crtcs[i];
-
-               if (!crtc || !crtc->state->mode_changed)
+               if (!crtc->state->mode_changed)
                        continue;
 
                funcs = crtc->helper_private;
@@ -731,16 +685,13 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
                }
        }
 
-       for (i = 0; i < old_state->num_connector; i++) {
-               struct drm_connector *connector;
+       for_each_connector_in_state(old_state, connector, old_conn_state, i) {
+               const struct drm_encoder_helper_funcs *funcs;
                struct drm_crtc_state *new_crtc_state;
-               struct drm_encoder_helper_funcs *funcs;
                struct drm_encoder *encoder;
                struct drm_display_mode *mode, *adjusted_mode;
 
-               connector = old_state->connectors[i];
-
-               if (!connector || !connector->state->best_encoder)
+               if (!connector->state->best_encoder)
                        continue;
 
                encoder = connector->state->best_encoder;
@@ -757,7 +708,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
 
                /*
                 * Each encoder has at most one connector (since we always steal
-                * it away), so we won't call call mode_set hooks twice.
+                * it away), so we won't call mode_set hooks twice.
                 */
                if (funcs->mode_set)
                        funcs->mode_set(encoder, mode, adjusted_mode);
@@ -808,17 +759,17 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_disables);
 void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
                                              struct drm_atomic_state *old_state)
 {
-       int ncrtcs = old_state->dev->mode_config.num_crtc;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *old_crtc_state;
+       struct drm_connector *connector;
+       struct drm_connector_state *old_conn_state;
        int i;
 
-       for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
-               struct drm_crtc *crtc;
-
-               crtc = old_state->crtcs[i];
+       for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
+               const struct drm_crtc_helper_funcs *funcs;
 
                /* Need to filter out CRTCs where only planes change. */
-               if (!crtc || !needs_modeset(crtc->state))
+               if (!needs_modeset(crtc->state))
                        continue;
 
                if (!crtc->state->active)
@@ -837,17 +788,15 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
                }
        }
 
-       for (i = 0; i < old_state->num_connector; i++) {
-               struct drm_connector *connector;
-               struct drm_encoder_helper_funcs *funcs;
+       for_each_connector_in_state(old_state, connector, old_conn_state, i) {
+               const struct drm_encoder_helper_funcs *funcs;
                struct drm_encoder *encoder;
 
-               connector = old_state->connectors[i];
-
-               if (!connector || !connector->state->best_encoder)
+               if (!connector->state->best_encoder)
                        continue;
 
-               if (!connector->state->crtc->state->active)
+               if (!connector->state->crtc->state->active ||
+                   !needs_modeset(connector->state->crtc->state))
                        continue;
 
                encoder = connector->state->best_encoder;
@@ -858,7 +807,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
 
                /*
                 * Each encoder has at most one connector (since we always steal
-                * it away), so we won't call call enable hooks twice.
+                * it away), so we won't call enable hooks twice.
                 */
                if (encoder->bridge)
                        encoder->bridge->funcs->pre_enable(encoder->bridge);
@@ -877,13 +826,12 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables);
 static void wait_for_fences(struct drm_device *dev,
                            struct drm_atomic_state *state)
 {
-       int nplanes = dev->mode_config.num_total_plane;
+       struct drm_plane *plane;
+       struct drm_plane_state *plane_state;
        int i;
 
-       for (i = 0; i < nplanes; i++) {
-               struct drm_plane *plane = state->planes[i];
-
-               if (!plane || !plane->state->fence)
+       for_each_plane_in_state(state, plane, plane_state, i) {
+               if (!plane->state->fence)
                        continue;
 
                WARN_ON(!plane->state->fb);
@@ -900,16 +848,9 @@ static bool framebuffer_changed(struct drm_device *dev,
 {
        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;
-
+       for_each_plane_in_state(old_state, plane, old_plane_state, i) {
                if (plane->state->crtc != crtc &&
                    old_plane_state->crtc != crtc)
                        continue;
@@ -938,16 +879,9 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
 {
        struct drm_crtc *crtc;
        struct drm_crtc_state *old_crtc_state;
-       int ncrtcs = old_state->dev->mode_config.num_crtc;
        int i, ret;
 
-       for (i = 0; i < ncrtcs; i++) {
-               crtc = old_state->crtcs[i];
-               old_crtc_state = old_state->crtc_states[i];
-
-               if (!crtc)
-                       continue;
-
+       for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
                /* No one cares about the old state, so abuse it for tracking
                 * and store whether we hold a vblank reference (and should do a
                 * vblank wait) in the ->enable boolean. */
@@ -972,11 +906,8 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
                old_crtc_state->last_vblank_count = drm_vblank_count(dev, i);
        }
 
-       for (i = 0; i < ncrtcs; i++) {
-               crtc = old_state->crtcs[i];
-               old_crtc_state = old_state->crtc_states[i];
-
-               if (!crtc || !old_crtc_state->enable)
+       for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
+               if (!old_crtc_state->enable)
                        continue;
 
                ret = wait_event_timeout(dev->vblank[i].queue,
@@ -1025,7 +956,7 @@ int drm_atomic_helper_commit(struct drm_device *dev,
 
        /*
         * Everything below can be run asynchronously without the need to grab
-        * any modeset locks at all under one conditions: It must be guaranteed
+        * any modeset locks at all under one condition: 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
@@ -1114,7 +1045,7 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev,
        int ret, i;
 
        for (i = 0; i < nplanes; i++) {
-               struct drm_plane_helper_funcs *funcs;
+               const struct drm_plane_helper_funcs *funcs;
                struct drm_plane *plane = state->planes[i];
                struct drm_plane_state *plane_state = state->plane_states[i];
                struct drm_framebuffer *fb;
@@ -1137,7 +1068,7 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev,
 
 fail:
        for (i--; i >= 0; i--) {
-               struct drm_plane_helper_funcs *funcs;
+               const struct drm_plane_helper_funcs *funcs;
                struct drm_plane *plane = state->planes[i];
                struct drm_plane_state *plane_state = state->plane_states[i];
                struct drm_framebuffer *fb;
@@ -1174,16 +1105,14 @@ EXPORT_SYMBOL(drm_atomic_helper_prepare_planes);
 void drm_atomic_helper_commit_planes(struct drm_device *dev,
                                     struct drm_atomic_state *old_state)
 {
-       int nplanes = dev->mode_config.num_total_plane;
-       int ncrtcs = dev->mode_config.num_crtc;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *old_crtc_state;
+       struct drm_plane *plane;
+       struct drm_plane_state *old_plane_state;
        int i;
 
-       for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
-               struct drm_crtc *crtc = old_state->crtcs[i];
-
-               if (!crtc)
-                       continue;
+       for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
+               const struct drm_crtc_helper_funcs *funcs;
 
                funcs = crtc->helper_private;
 
@@ -1193,13 +1122,8 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
                funcs->atomic_begin(crtc);
        }
 
-       for (i = 0; i < nplanes; i++) {
-               struct drm_plane_helper_funcs *funcs;
-               struct drm_plane *plane = old_state->planes[i];
-               struct drm_plane_state *old_plane_state;
-
-               if (!plane)
-                       continue;
+       for_each_plane_in_state(old_state, plane, old_plane_state, i) {
+               const struct drm_plane_helper_funcs *funcs;
 
                funcs = plane->helper_private;
 
@@ -1218,12 +1142,8 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
                        funcs->atomic_update(plane, old_plane_state);
        }
 
-       for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc_helper_funcs *funcs;
-               struct drm_crtc *crtc = old_state->crtcs[i];
-
-               if (!crtc)
-                       continue;
+       for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
+               const struct drm_crtc_helper_funcs *funcs;
 
                funcs = crtc->helper_private;
 
@@ -1250,18 +1170,14 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_planes);
 void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
                                      struct drm_atomic_state *old_state)
 {
-       int nplanes = dev->mode_config.num_total_plane;
+       struct drm_plane *plane;
+       struct drm_plane_state *plane_state;
        int i;
 
-       for (i = 0; i < nplanes; i++) {
-               struct drm_plane_helper_funcs *funcs;
-               struct drm_plane *plane = old_state->planes[i];
-               struct drm_plane_state *plane_state = old_state->plane_states[i];
+       for_each_plane_in_state(old_state, plane, plane_state, i) {
+               const struct drm_plane_helper_funcs *funcs;
                struct drm_framebuffer *old_fb;
 
-               if (!plane)
-                       continue;
-
                funcs = plane->helper_private;
 
                old_fb = plane_state->fb;
@@ -1510,8 +1426,10 @@ static int update_output_state(struct drm_atomic_state *state,
                               struct drm_mode_set *set)
 {
        struct drm_device *dev = set->crtc->dev;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *crtc_state;
+       struct drm_connector *connector;
        struct drm_connector_state *conn_state;
-       int ncrtcs = state->dev->mode_config.num_crtc;
        int ret, i, j;
 
        ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
@@ -1527,27 +1445,14 @@ static int update_output_state(struct drm_atomic_state *state,
                        return PTR_ERR(conn_state);
        }
 
-       for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc *crtc = state->crtcs[i];
-
-               if (!crtc)
-                       continue;
-
+       for_each_crtc_in_state(state, crtc, crtc_state, i) {
                ret = drm_atomic_add_affected_connectors(state, crtc);
                if (ret)
                        return ret;
        }
 
        /* Then recompute connector->crtc links and crtc enabling state. */
-       for (i = 0; i < state->num_connector; i++) {
-               struct drm_connector *connector;
-
-               connector = state->connectors[i];
-               conn_state = state->connector_states[i];
-
-               if (!connector)
-                       continue;
-
+       for_each_connector_in_state(state, connector, conn_state, i) {
                if (conn_state->crtc == set->crtc) {
                        ret = drm_atomic_set_crtc_for_connector(conn_state,
                                                                NULL);
@@ -1566,13 +1471,7 @@ static int update_output_state(struct drm_atomic_state *state,
                }
        }
 
-       for (i = 0; i < ncrtcs; i++) {
-               struct drm_crtc *crtc = state->crtcs[i];
-               struct drm_crtc_state *crtc_state = state->crtc_states[i];
-
-               if (!crtc)
-                       continue;
-
+       for_each_crtc_in_state(state, crtc, crtc_state, i) {
                /* Don't update ->enable for the CRTC in the set_config request,
                 * since a mismatch would indicate a bug in the upper layers.
                 * The actual modeset code later on will catch any
@@ -2001,10 +1900,10 @@ retry:
        WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
 
        list_for_each_entry(tmp_connector, &config->connector_list, head) {
-               if (connector->state->crtc != crtc)
+               if (tmp_connector->state->crtc != crtc)
                        continue;
 
-               if (connector->dpms == DRM_MODE_DPMS_ON) {
+               if (tmp_connector->dpms == DRM_MODE_DPMS_ON) {
                        active = true;
                        break;
                }
@@ -2066,6 +1965,26 @@ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
 }
 EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
 
+/**
+ * __drm_atomic_helper_crtc_duplicate_state - copy atomic CRTC state
+ * @crtc: CRTC object
+ * @state: atomic CRTC state
+ *
+ * Copies atomic state from a CRTC's current state and resets inferred values.
+ * This is useful for drivers that subclass the CRTC state.
+ */
+void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
+                                             struct drm_crtc_state *state)
+{
+       memcpy(state, crtc->state, sizeof(*state));
+
+       state->mode_changed = false;
+       state->active_changed = false;
+       state->planes_changed = false;
+       state->event = NULL;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
+
 /**
  * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook
  * @crtc: drm CRTC
@@ -2081,19 +2000,34 @@ drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
        if (WARN_ON(!crtc->state))
                return NULL;
 
-       state = kmemdup(crtc->state, sizeof(*crtc->state), GFP_KERNEL);
-
-       if (state) {
-               state->mode_changed = false;
-               state->active_changed = false;
-               state->planes_changed = false;
-               state->event = NULL;
-       }
+       state = kmalloc(sizeof(*state), GFP_KERNEL);
+       if (state)
+               __drm_atomic_helper_crtc_duplicate_state(crtc, state);
 
        return state;
 }
 EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
 
+/**
+ * __drm_atomic_helper_crtc_destroy_state - release CRTC state
+ * @crtc: CRTC object
+ * @state: CRTC state object to release
+ *
+ * Releases all resources stored in the CRTC state without actually freeing
+ * the memory of the CRTC state. This is useful for drivers that subclass the
+ * CRTC state.
+ */
+void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
+                                           struct drm_crtc_state *state)
+{
+       /*
+        * This is currently a placeholder so that drivers that subclass the
+        * state will automatically do the right thing if code is ever added
+        * to this function.
+        */
+}
+EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
+
 /**
  * drm_atomic_helper_crtc_destroy_state - default state destroy hook
  * @crtc: drm CRTC
@@ -2105,6 +2039,7 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
 void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
                                          struct drm_crtc_state *state)
 {
+       __drm_atomic_helper_crtc_destroy_state(crtc, state);
        kfree(state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
@@ -2129,6 +2064,24 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane)
 }
 EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
 
+/**
+ * __drm_atomic_helper_plane_duplicate_state - copy atomic plane state
+ * @plane: plane object
+ * @state: atomic plane state
+ *
+ * Copies atomic state from a plane's current state. This is useful for
+ * drivers that subclass the plane state.
+ */
+void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
+                                              struct drm_plane_state *state)
+{
+       memcpy(state, plane->state, sizeof(*state));
+
+       if (state->fb)
+               drm_framebuffer_reference(state->fb);
+}
+EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
+
 /**
  * drm_atomic_helper_plane_duplicate_state - default state duplicate hook
  * @plane: drm plane
@@ -2144,15 +2097,31 @@ drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
        if (WARN_ON(!plane->state))
                return NULL;
 
-       state = kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL);
-
-       if (state && state->fb)
-               drm_framebuffer_reference(state->fb);
+       state = kmalloc(sizeof(*state), GFP_KERNEL);
+       if (state)
+               __drm_atomic_helper_plane_duplicate_state(plane, state);
 
        return state;
 }
 EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
 
+/**
+ * __drm_atomic_helper_plane_destroy_state - release plane state
+ * @plane: plane object
+ * @state: plane state object to release
+ *
+ * Releases all resources stored in the plane state without actually freeing
+ * the memory of the plane state. This is useful for drivers that subclass the
+ * plane state.
+ */
+void __drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
+                                            struct drm_plane_state *state)
+{
+       if (state->fb)
+               drm_framebuffer_unreference(state->fb);
+}
+EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state);
+
 /**
  * drm_atomic_helper_plane_destroy_state - default state destroy hook
  * @plane: drm plane
@@ -2164,9 +2133,7 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
 void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
                                           struct drm_plane_state *state)
 {
-       if (state->fb)
-               drm_framebuffer_unreference(state->fb);
-
+       __drm_atomic_helper_plane_destroy_state(plane, state);
        kfree(state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
@@ -2189,6 +2156,22 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector)
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
 
+/**
+ * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
+ * @connector: connector object
+ * @state: atomic connector state
+ *
+ * Copies atomic state from a connector's current state. This is useful for
+ * drivers that subclass the connector state.
+ */
+void
+__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
+                                           struct drm_connector_state *state)
+{
+       memcpy(state, connector->state, sizeof(*state));
+}
+EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state);
+
 /**
  * drm_atomic_helper_connector_duplicate_state - default state duplicate hook
  * @connector: drm connector
@@ -2199,13 +2182,40 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
 struct drm_connector_state *
 drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector)
 {
+       struct drm_connector_state *state;
+
        if (WARN_ON(!connector->state))
                return NULL;
 
-       return kmemdup(connector->state, sizeof(*connector->state), GFP_KERNEL);
+       state = kmalloc(sizeof(*state), GFP_KERNEL);
+       if (state)
+               __drm_atomic_helper_connector_duplicate_state(connector, state);
+
+       return state;
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
 
+/**
+ * __drm_atomic_helper_connector_destroy_state - release connector state
+ * @connector: connector object
+ * @state: connector state object to release
+ *
+ * Releases all resources stored in the connector state without actually
+ * freeing the memory of the connector state. This is useful for drivers that
+ * subclass the connector state.
+ */
+void
+__drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
+                                           struct drm_connector_state *state)
+{
+       /*
+        * This is currently a placeholder so that drivers that subclass the
+        * state will automatically do the right thing if code is ever added
+        * to this function.
+        */
+}
+EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state);
+
 /**
  * drm_atomic_helper_connector_destroy_state - default state destroy hook
  * @connector: drm connector
@@ -2217,6 +2227,7 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
 void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
                                          struct drm_connector_state *state)
 {
+       __drm_atomic_helper_connector_destroy_state(connector, state);
        kfree(state);
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
index d1187e571c6dd038648aa86b73d0cb2ddd526792..eaa5790c2a6f89a384f01d398bef81ef74cacb48 100644 (file)
@@ -49,7 +49,7 @@ void drm_bridge_remove(struct drm_bridge *bridge)
 }
 EXPORT_SYMBOL(drm_bridge_remove);
 
-extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
+int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
 {
        if (!dev || !bridge)
                return -EINVAL;
index 9f970c2d481912d3db2adb498940c6dcf7ca9b4a..3403edea9076b0233d459fc675c92b119cb922bb 100644 (file)
@@ -660,6 +660,9 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
        struct drm_mode_config *config = &dev->mode_config;
        int ret;
 
+       WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY);
+       WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR);
+
        crtc->dev = dev;
        crtc->funcs = funcs;
        crtc->invert_dimensions = false;
@@ -2479,6 +2482,17 @@ static int __setplane_internal(struct drm_plane *plane,
                goto out;
        }
 
+       /* Give drivers some help against integer overflows */
+       if (crtc_w > INT_MAX ||
+           crtc_x > INT_MAX - (int32_t) crtc_w ||
+           crtc_h > INT_MAX ||
+           crtc_y > INT_MAX - (int32_t) crtc_h) {
+               DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
+                             crtc_w, crtc_h, crtc_x, crtc_y);
+               return -ERANGE;
+       }
+
+
        fb_width = fb->width << 16;
        fb_height = fb->height << 16;
 
@@ -2563,17 +2577,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
 
-       /* Give drivers some help against integer overflows */
-       if (plane_req->crtc_w > INT_MAX ||
-           plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w ||
-           plane_req->crtc_h > INT_MAX ||
-           plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) {
-               DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
-                             plane_req->crtc_w, plane_req->crtc_h,
-                             plane_req->crtc_x, plane_req->crtc_y);
-               return -ERANGE;
-       }
-
        /*
         * First, find the plane, crtc, and fb objects.  If not available,
         * we don't bother to call the driver.
@@ -5596,6 +5599,7 @@ struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
        mutex_unlock(&dev->mode_config.idr_mutex);
        return NULL;
 }
+EXPORT_SYMBOL(drm_mode_get_tile_group);
 
 /**
  * drm_mode_create_tile_group - create a tile group from a displayid description
@@ -5634,3 +5638,4 @@ struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
        mutex_unlock(&dev->mode_config.idr_mutex);
        return tg;
 }
+EXPORT_SYMBOL(drm_mode_create_tile_group);
index 3053aab968f9b52ccf7f30976a796ee54262d974..ab00286aec938ddc737c0588e46cf4616526c20f 100644 (file)
@@ -161,7 +161,7 @@ EXPORT_SYMBOL(drm_helper_crtc_in_use);
 static void
 drm_encoder_disable(struct drm_encoder *encoder)
 {
-       struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
+       const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
 
        if (encoder->bridge)
                encoder->bridge->funcs->disable(encoder->bridge);
@@ -191,7 +191,7 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev)
        }
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+               const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
                crtc->enabled = drm_helper_crtc_in_use(crtc);
                if (!crtc->enabled) {
                        if (crtc_funcs->disable)
@@ -229,7 +229,7 @@ EXPORT_SYMBOL(drm_helper_disable_unused_functions);
 static void
 drm_crtc_prepare_encoders(struct drm_device *dev)
 {
-       struct drm_encoder_helper_funcs *encoder_funcs;
+       const struct drm_encoder_helper_funcs *encoder_funcs;
        struct drm_encoder *encoder;
 
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
@@ -270,9 +270,9 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
                              struct drm_framebuffer *old_fb)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_display_mode *adjusted_mode, saved_mode;
-       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
-       struct drm_encoder_helper_funcs *encoder_funcs;
+       struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;
+       const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+       const struct drm_encoder_helper_funcs *encoder_funcs;
        int saved_x, saved_y;
        bool saved_enabled;
        struct drm_encoder *encoder;
@@ -292,6 +292,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
        }
 
        saved_mode = crtc->mode;
+       saved_hwmode = crtc->hwmode;
        saved_x = crtc->x;
        saved_y = crtc->y;
 
@@ -334,6 +335,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
        }
        DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
 
+       crtc->hwmode = *adjusted_mode;
+
        /* Prepare the encoders and CRTCs before setting the mode. */
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
 
@@ -396,9 +399,6 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
                        encoder->bridge->funcs->enable(encoder->bridge);
        }
 
-       /* Store real post-adjustment hardware mode. */
-       crtc->hwmode = *adjusted_mode;
-
        /* Calculate and store various constants which
         * are later needed by vblank and swap-completion
         * timestamping. They are derived from true hwmode.
@@ -411,6 +411,7 @@ done:
        if (!ret) {
                crtc->enabled = saved_enabled;
                crtc->mode = saved_mode;
+               crtc->hwmode = saved_hwmode;
                crtc->x = saved_x;
                crtc->y = saved_y;
        }
@@ -472,7 +473,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
        bool fb_changed = false; /* if true and !mode_changed just do a flip */
        struct drm_connector *save_connectors, *connector;
        int count = 0, ro, fail = 0;
-       struct drm_crtc_helper_funcs *crtc_funcs;
+       const struct drm_crtc_helper_funcs *crtc_funcs;
        struct drm_mode_set save_set;
        int ret;
        int i;
@@ -572,7 +573,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
        /* a) traverse passed in connector list and get encoders for them */
        count = 0;
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               struct drm_connector_helper_funcs *connector_funcs =
+               const struct drm_connector_helper_funcs *connector_funcs =
                        connector->helper_private;
                new_encoder = connector->encoder;
                for (ro = 0; ro < set->num_connectors; ro++) {
@@ -732,7 +733,7 @@ static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)
 static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
        struct drm_bridge *bridge = encoder->bridge;
-       struct drm_encoder_helper_funcs *encoder_funcs;
+       const struct drm_encoder_helper_funcs *encoder_funcs;
 
        if (bridge) {
                if (mode == DRM_MODE_DPMS_ON)
@@ -794,7 +795,7 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
        /* from off to on, do crtc then encoder */
        if (mode < old_dpms) {
                if (crtc) {
-                       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+                       const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
                        if (crtc_funcs->dpms)
                                (*crtc_funcs->dpms) (crtc,
                                                     drm_helper_choose_crtc_dpms(crtc));
@@ -808,7 +809,7 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
                if (encoder)
                        drm_helper_encoder_dpms(encoder, encoder_dpms);
                if (crtc) {
-                       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+                       const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
                        if (crtc_funcs->dpms)
                                (*crtc_funcs->dpms) (crtc,
                                                     drm_helper_choose_crtc_dpms(crtc));
@@ -870,7 +871,7 @@ void drm_helper_resume_force_mode(struct drm_device *dev)
 {
        struct drm_crtc *crtc;
        struct drm_encoder *encoder;
-       struct drm_crtc_helper_funcs *crtc_funcs;
+       const struct drm_crtc_helper_funcs *crtc_funcs;
        int encoder_dpms;
        bool ret;
 
@@ -935,7 +936,7 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod
                             struct drm_framebuffer *old_fb)
 {
        struct drm_crtc_state *crtc_state;
-       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+       const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
        int ret;
 
        if (crtc->funcs->atomic_duplicate_state)
index f1283878ff6df3000608773de43ee22e77cd7b59..71dcbc64ae98b860bbb4a6aed06f502dc83737f1 100644 (file)
@@ -427,11 +427,13 @@ static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter)
  * retrying the transaction as appropriate.  It is assumed that the
  * aux->transfer function does not modify anything in the msg other than the
  * reply field.
+ *
+ * Returns bytes transferred on success, or a negative error code on failure.
  */
 static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 {
        unsigned int retry;
-       int err;
+       int ret;
 
        /*
         * DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device
@@ -440,14 +442,14 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
         */
        for (retry = 0; retry < 7; retry++) {
                mutex_lock(&aux->hw_mutex);
-               err = aux->transfer(aux, msg);
+               ret = aux->transfer(aux, msg);
                mutex_unlock(&aux->hw_mutex);
-               if (err < 0) {
-                       if (err == -EBUSY)
+               if (ret < 0) {
+                       if (ret == -EBUSY)
                                continue;
 
-                       DRM_DEBUG_KMS("transaction failed: %d\n", err);
-                       return err;
+                       DRM_DEBUG_KMS("transaction failed: %d\n", ret);
+                       return ret;
                }
 
 
@@ -460,7 +462,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
                        break;
 
                case DP_AUX_NATIVE_REPLY_NACK:
-                       DRM_DEBUG_KMS("native nack\n");
+                       DRM_DEBUG_KMS("native nack (result=%d, size=%zu)\n", ret, msg->size);
                        return -EREMOTEIO;
 
                case DP_AUX_NATIVE_REPLY_DEFER:
@@ -488,12 +490,10 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
                         * Both native ACK and I2C ACK replies received. We
                         * can assume the transfer was successful.
                         */
-                       if (err < msg->size)
-                               return -EPROTO;
-                       return 0;
+                       return ret;
 
                case DP_AUX_I2C_REPLY_NACK:
-                       DRM_DEBUG_KMS("I2C nack\n");
+                       DRM_DEBUG_KMS("I2C nack (result=%d, size=%zu\n", ret, msg->size);
                        aux->i2c_nack_count++;
                        return -EREMOTEIO;
 
@@ -513,14 +513,55 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
        return -EREMOTEIO;
 }
 
+/*
+ * Keep retrying drm_dp_i2c_do_msg until all data has been transferred.
+ *
+ * Returns an error code on failure, or a recommended transfer size on success.
+ */
+static int drm_dp_i2c_drain_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *orig_msg)
+{
+       int err, ret = orig_msg->size;
+       struct drm_dp_aux_msg msg = *orig_msg;
+
+       while (msg.size > 0) {
+               err = drm_dp_i2c_do_msg(aux, &msg);
+               if (err <= 0)
+                       return err == 0 ? -EPROTO : err;
+
+               if (err < msg.size && err < ret) {
+                       DRM_DEBUG_KMS("Partial I2C reply: requested %zu bytes got %d bytes\n",
+                                     msg.size, err);
+                       ret = err;
+               }
+
+               msg.size -= err;
+               msg.buffer += err;
+       }
+
+       return ret;
+}
+
+/*
+ * Bizlink designed DP->DVI-D Dual Link adapters require the I2C over AUX
+ * packets to be as large as possible. If not, the I2C transactions never
+ * succeed. Hence the default is maximum.
+ */
+static int dp_aux_i2c_transfer_size __read_mostly = DP_AUX_MAX_PAYLOAD_BYTES;
+module_param_unsafe(dp_aux_i2c_transfer_size, int, 0644);
+MODULE_PARM_DESC(dp_aux_i2c_transfer_size,
+                "Number of bytes to transfer in a single I2C over DP AUX CH message, (1-16, default 16)");
+
 static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
                           int num)
 {
        struct drm_dp_aux *aux = adapter->algo_data;
        unsigned int i, j;
+       unsigned transfer_size;
        struct drm_dp_aux_msg msg;
        int err = 0;
 
+       dp_aux_i2c_transfer_size = clamp(dp_aux_i2c_transfer_size, 1, DP_AUX_MAX_PAYLOAD_BYTES);
+
        memset(&msg, 0, sizeof(msg));
 
        for (i = 0; i < num; i++) {
@@ -538,20 +579,19 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
                err = drm_dp_i2c_do_msg(aux, &msg);
                if (err < 0)
                        break;
-               /*
-                * Many hardware implementations support FIFOs larger than a
-                * single byte, but it has been empirically determined that
-                * transferring data in larger chunks can actually lead to
-                * decreased performance. Therefore each message is simply
-                * transferred byte-by-byte.
+               /* We want each transaction to be as large as possible, but
+                * we'll go to smaller sizes if the hardware gives us a
+                * short reply.
                 */
-               for (j = 0; j < msgs[i].len; j++) {
+               transfer_size = dp_aux_i2c_transfer_size;
+               for (j = 0; j < msgs[i].len; j += msg.size) {
                        msg.buffer = msgs[i].buf + j;
-                       msg.size = 1;
+                       msg.size = min(transfer_size, msgs[i].len - j);
 
-                       err = drm_dp_i2c_do_msg(aux, &msg);
+                       err = drm_dp_i2c_drain_msg(aux, &msg);
                        if (err < 0)
                                break;
+                       transfer_size = err;
                }
                if (err < 0)
                        break;
index 379ab45557568c6e21615526a96a60e145ed1ee5..132581ca4ad84fff6b25abe13d84af96f0c1c11b 100644 (file)
@@ -2324,6 +2324,19 @@ out:
 }
 EXPORT_SYMBOL(drm_dp_mst_allocate_vcpi);
 
+int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port)
+{
+       int slots = 0;
+       port = drm_dp_get_validated_port_ref(mgr, port);
+       if (!port)
+               return slots;
+
+       slots = port->vcpi.num_slots;
+       drm_dp_put_port(port);
+       return slots;
+}
+EXPORT_SYMBOL(drm_dp_mst_get_vcpi_slots);
+
 /**
  * drm_dp_mst_reset_vcpi_slots() - Reset number of slots to 0 for VCPI
  * @mgr: manager for this port
index d51213464672a9c1b7d3362f355b6ddde29c2403..48f7359e2a6bfed94791c98f78431aab824f7b94 100644 (file)
@@ -70,7 +70,7 @@ void drm_err(const char *format, ...)
        vaf.fmt = format;
        vaf.va = &args;
 
-       printk(KERN_ERR "[" DRM_NAME ":%pf] *ERROR* %pV",
+       printk(KERN_ERR "[" DRM_NAME ":%ps] *ERROR* %pV",
               __builtin_return_address(0), &vaf);
 
        va_end(args);
index 732cb6f8e653f58dee7102f0bb11b797cde2f5ad..4c0aa97aaf0399a111fe0d63be6d996bafbfd7f3 100644 (file)
@@ -287,6 +287,7 @@ int drm_load_edid_firmware(struct drm_connector *connector)
 
        drm_mode_connector_update_edid_property(connector, edid);
        ret = drm_add_edid_modes(connector, edid);
+       drm_edid_to_eld(connector, edid);
        kfree(edid);
 
        return ret;
index cc0ae047ed3bd8fcc265e38a06d8ec86207deb55..5c1aca443e54f851cf7abeb9679962f3ec96ef29 100644 (file)
@@ -304,7 +304,7 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
        }
 
        drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
-       drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
+       drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
 
        offset = fbi->var.xoffset * bytes_per_pixel;
        offset += fbi->var.yoffset * fb->pitches[0];
index 1e6a0c760c5df9447852672728739225ce48b63b..cac422916c7afbbaf38095354784fa3d81632294 100644 (file)
@@ -238,7 +238,7 @@ static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
 int drm_fb_helper_debug_enter(struct fb_info *info)
 {
        struct drm_fb_helper *helper = info->par;
-       struct drm_crtc_helper_funcs *funcs;
+       const struct drm_crtc_helper_funcs *funcs;
        int i;
 
        list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
@@ -285,7 +285,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
 {
        struct drm_fb_helper *helper = info->par;
        struct drm_crtc *crtc;
-       struct drm_crtc_helper_funcs *funcs;
+       const struct drm_crtc_helper_funcs *funcs;
        struct drm_framebuffer *fb;
        int i;
 
@@ -765,7 +765,7 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
 {
        struct drm_fb_helper *fb_helper = info->par;
        struct drm_device *dev = fb_helper->dev;
-       struct drm_crtc_helper_funcs *crtc_funcs;
+       const struct drm_crtc_helper_funcs *crtc_funcs;
        u16 *red, *green, *blue, *transp;
        struct drm_crtc *crtc;
        int i, j, rc = 0;
@@ -1034,23 +1034,45 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
        crtc_count = 0;
        for (i = 0; i < fb_helper->crtc_count; i++) {
                struct drm_display_mode *desired_mode;
-               int x, y;
+               struct drm_mode_set *mode_set;
+               int x, y, j;
+               /* in case of tile group, are we the last tile vert or horiz?
+                * If no tile group you are always the last one both vertically
+                * and horizontally
+                */
+               bool lastv = true, lasth = true;
+
                desired_mode = fb_helper->crtc_info[i].desired_mode;
+               mode_set = &fb_helper->crtc_info[i].mode_set;
+
+               if (!desired_mode)
+                       continue;
+
+               crtc_count++;
+
                x = fb_helper->crtc_info[i].x;
                y = fb_helper->crtc_info[i].y;
-               if (desired_mode) {
-                       if (gamma_size == 0)
-                               gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
-                       if (desired_mode->hdisplay + x < sizes.fb_width)
-                               sizes.fb_width = desired_mode->hdisplay + x;
-                       if (desired_mode->vdisplay + y < sizes.fb_height)
-                               sizes.fb_height = desired_mode->vdisplay + y;
-                       if (desired_mode->hdisplay + x > sizes.surface_width)
-                               sizes.surface_width = desired_mode->hdisplay + x;
-                       if (desired_mode->vdisplay + y > sizes.surface_height)
-                               sizes.surface_height = desired_mode->vdisplay + y;
-                       crtc_count++;
+
+               if (gamma_size == 0)
+                       gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
+
+               sizes.surface_width  = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width);
+               sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height);
+
+               for (j = 0; j < mode_set->num_connectors; j++) {
+                       struct drm_connector *connector = mode_set->connectors[j];
+                       if (connector->has_tile) {
+                               lasth = (connector->tile_h_loc == (connector->num_h_tile - 1));
+                               lastv = (connector->tile_v_loc == (connector->num_v_tile - 1));
+                               /* cloning to multiple tiles is just crazy-talk, so: */
+                               break;
+                       }
                }
+
+               if (lasth)
+                       sizes.fb_width  = min_t(u32, desired_mode->hdisplay + x, sizes.fb_width);
+               if (lastv)
+                       sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height);
        }
 
        if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
@@ -1261,12 +1283,12 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
                                                      int width, int height)
 {
        struct drm_cmdline_mode *cmdline_mode;
-       struct drm_display_mode *mode = NULL;
+       struct drm_display_mode *mode;
        bool prefer_non_interlace;
 
        cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
        if (cmdline_mode->specified == false)
-               return mode;
+               return NULL;
 
        /* attempt to find a matching mode in the list of modes
         *  we have gotten so far, if not add a CVT mode that conforms
@@ -1275,7 +1297,7 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
                goto create_mode;
 
        prefer_non_interlace = !cmdline_mode->interlace;
- again:
+again:
        list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
                /* check width/height */
                if (mode->hdisplay != cmdline_mode->xres ||
@@ -1529,7 +1551,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
        int c, o;
        struct drm_device *dev = fb_helper->dev;
        struct drm_connector *connector;
-       struct drm_connector_helper_funcs *connector_funcs;
+       const struct drm_connector_helper_funcs *connector_funcs;
        struct drm_encoder *encoder;
        int my_score, best_score, score;
        struct drm_fb_helper_crtc **crtcs, *crtc;
index f1b32f91d94163bcdca46a6ee5f29bd789e23336..cbb4fc0fc969ee2236e112cbb5974742ceffc191 100644 (file)
@@ -37,6 +37,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_gem.h>
 
+#include "drm_internal.h"
 #include "drm_legacy.h"
 
 /**
index 2f4c4343dfa32f5a3f2c81e83a67f9409a31e11f..aa8bbb460c5715a619988d6d4350b4a4507173f8 100644 (file)
@@ -1016,7 +1016,7 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd,
        return 0;
 }
 
-drm_ioctl_compat_t *drm_compat_ioctls[] = {
+static drm_ioctl_compat_t *drm_compat_ioctls[] = {
        [DRM_IOCTL_NR(DRM_IOCTL_VERSION32)] = compat_drm_version,
        [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE32)] = compat_drm_getunique,
        [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP32)] = compat_drm_getmap,
index a6d773a61c2d2527dd6a8262435f4e8e6b3339cb..266dcd6cdf3bf3ad1d487ad70110496b294e5491 100644 (file)
@@ -524,8 +524,13 @@ static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv)
        return 0;
 }
 
-#define DRM_IOCTL_DEF(ioctl, _func, _flags) \
-       [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0, .name = #ioctl}
+#define DRM_IOCTL_DEF(ioctl, _func, _flags)    \
+       [DRM_IOCTL_NR(ioctl)] = {               \
+               .cmd = ioctl,                   \
+               .func = _func,                  \
+               .flags = _flags,                \
+               .name = #ioctl                  \
+       }
 
 /** Ioctl table */
 static const struct drm_ioctl_desc drm_ioctls[] = {
@@ -663,39 +668,29 @@ long drm_ioctl(struct file *filp,
        int retcode = -EINVAL;
        char stack_kdata[128];
        char *kdata = NULL;
-       unsigned int usize, asize;
+       unsigned int usize, asize, drv_size;
 
        dev = file_priv->minor->dev;
 
        if (drm_device_is_unplugged(dev))
                return -ENODEV;
 
-       if ((nr >= DRM_CORE_IOCTL_COUNT) &&
-           ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END)))
-               goto err_i1;
-       if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) &&
-           (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) {
-               u32 drv_size;
+       if (nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END) {
+               /* driver ioctl */
+               if (nr - DRM_COMMAND_BASE >= dev->driver->num_ioctls)
+                       goto err_i1;
                ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
-               drv_size = _IOC_SIZE(ioctl->cmd_drv);
-               usize = asize = _IOC_SIZE(cmd);
-               if (drv_size > asize)
-                       asize = drv_size;
-               cmd = ioctl->cmd_drv;
-       }
-       else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) {
-               u32 drv_size;
-
+       } else {
+               /* core ioctl */
+               if (nr >= DRM_CORE_IOCTL_COUNT)
+                       goto err_i1;
                ioctl = &drm_ioctls[nr];
+       }
 
-               drv_size = _IOC_SIZE(ioctl->cmd);
-               usize = asize = _IOC_SIZE(cmd);
-               if (drv_size > asize)
-                       asize = drv_size;
-
-               cmd = ioctl->cmd;
-       } else
-               goto err_i1;
+       drv_size = _IOC_SIZE(ioctl->cmd);
+       usize = _IOC_SIZE(cmd);
+       asize = max(usize, drv_size);
+       cmd = ioctl->cmd;
 
        DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n",
                  task_pid_nr(current),
@@ -776,12 +771,13 @@ EXPORT_SYMBOL(drm_ioctl);
  */
 bool drm_ioctl_flags(unsigned int nr, unsigned int *flags)
 {
-       if ((nr >= DRM_COMMAND_END && nr < DRM_CORE_IOCTL_COUNT) ||
-           (nr < DRM_COMMAND_BASE)) {
-               *flags = drm_ioctls[nr].flags;
-               return true;
-       }
+       if (nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END)
+               return false;
+
+       if (nr >= DRM_CORE_IOCTL_COUNT)
+               return false;
 
-       return false;
+       *flags = drm_ioctls[nr].flags;
+       return true;
 }
 EXPORT_SYMBOL(drm_ioctl_flags);
index 2cca85f23138bf7a173a0f6f1204ccb5194533fc..213b11ea69b5b7ecc6309cdbde007d46e0319144 100644 (file)
@@ -903,6 +903,12 @@ EXPORT_SYMBOL(drm_mode_duplicate);
  */
 bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
 {
+       if (!mode1 && !mode2)
+               return true;
+
+       if (!mode1 || !mode2)
+               return false;
+
        /* do clock check convert to PICOS so fb modes get matched
         * the same */
        if (mode1->clock && mode2->clock) {
@@ -1148,7 +1154,7 @@ EXPORT_SYMBOL(drm_mode_sort);
 /**
  * drm_mode_connector_list_update - update the mode list for the connector
  * @connector: the connector to update
- * @merge_type_bits: whether to merge or overright type bits.
+ * @merge_type_bits: whether to merge or overwrite type bits
  *
  * This moves the modes from the @connector probed_modes list
  * to the actual mode list. It compares the probed mode against the current
index 16150a00c23728585d50ebc59747286633bca51a..aaa130736bf8d303bd949d0e5588b413e137b23d 100644 (file)
@@ -43,14 +43,10 @@ static uint32_t drm_crtc_port_mask(struct drm_device *dev,
 uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
                                    struct device_node *port)
 {
-       struct device_node *remote_port, *ep = NULL;
+       struct device_node *remote_port, *ep;
        uint32_t possible_crtcs = 0;
 
-       do {
-               ep = of_graph_get_next_endpoint(port, ep);
-               if (!ep)
-                       break;
-
+       for_each_endpoint_of_node(port, ep) {
                remote_port = of_graph_get_remote_port(ep);
                if (!remote_port) {
                        of_node_put(ep);
@@ -60,7 +56,7 @@ uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
                possible_crtcs |= drm_crtc_port_mask(dev, remote_port);
 
                of_node_put(remote_port);
-       } while (1);
+       }
 
        return possible_crtcs;
 }
index fd29f03645b8e465b42add64384b339c13229dc2..1b1bd42b03687683202eb600425c5d7e582c61ad 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/export.h>
 #include <drm/drmP.h>
+#include "drm_internal.h"
 #include "drm_legacy.h"
 
 /**
index b62b036350503c8eb70dee380342b097b796c2c7..40c1db9ad7c3fac84365cc331ec67661e902abb5 100644 (file)
@@ -353,13 +353,14 @@ static struct drm_plane *create_primary_plane(struct drm_device *dev)
        if (primary == NULL) {
                DRM_DEBUG_KMS("Failed to allocate primary plane\n");
                return NULL;
-               /*
-                * Remove the format_default field from drm_plane when dropping
-                * this helper.
-                */
-               primary->format_default = true;
        }
 
+       /*
+        * Remove the format_default field from drm_plane when dropping
+        * this helper.
+        */
+       primary->format_default = true;
+
        /* possible_crtc's will be filled in later by crtc_init */
        ret = drm_universal_plane_init(dev, primary, 0,
                                       &drm_primary_helper_funcs,
@@ -400,9 +401,9 @@ int drm_plane_helper_commit(struct drm_plane *plane,
                            struct drm_plane_state *plane_state,
                            struct drm_framebuffer *old_fb)
 {
-       struct drm_plane_helper_funcs *plane_funcs;
+       const struct drm_plane_helper_funcs *plane_funcs;
        struct drm_crtc *crtc[2];
-       struct drm_crtc_helper_funcs *crtc_funcs[2];
+       const struct drm_crtc_helper_funcs *crtc_funcs[2];
        int i, ret = 0;
 
        plane_funcs = plane->helper_private;
index 6591d48c1b9d0f3bcc4a74a8da730833cbc4e839..63503879a676cc07db6c417cad49017b02a59ca8 100644 (file)
@@ -98,7 +98,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
 {
        struct drm_device *dev = connector->dev;
        struct drm_display_mode *mode;
-       struct drm_connector_helper_funcs *connector_funcs =
+       const struct drm_connector_helper_funcs *connector_funcs =
                connector->helper_private;
        int count = 0;
        int mode_flags = 0;
@@ -174,6 +174,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
                        struct edid *edid = (struct edid *) connector->edid_blob_ptr->data;
 
                        count = drm_add_edid_modes(connector, edid);
+                       drm_edid_to_eld(connector, edid);
                } else
                        count = (*connector_funcs->get_modes)(connector);
        }
index 4a2c328959e59348ef7ee5f4bb0797835cd92ba5..aab49ee4ed40d2ce5b525554209fd3ffe40340b4 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/slab.h>
 #endif
 #include <asm/pgtable.h>
+#include "drm_internal.h"
 #include "drm_legacy.h"
 
 struct drm_vma_entry {
index 970046199608484365195ecdd78d27fecc57ed4b..1f7e33f59de69e3ecf6c4f4ac865c1746d491d8d 100644 (file)
@@ -28,6 +28,7 @@
 #include <video/exynos7_decon.h>
 
 #include "exynos_drm_crtc.h"
+#include "exynos_drm_plane.h"
 #include "exynos_drm_drv.h"
 #include "exynos_drm_fbdev.h"
 #include "exynos_drm_iommu.h"
 
 #define WINDOWS_NR     2
 
-struct decon_win_data {
-       unsigned int            ovl_x;
-       unsigned int            ovl_y;
-       unsigned int            offset_x;
-       unsigned int            offset_y;
-       unsigned int            ovl_width;
-       unsigned int            ovl_height;
-       unsigned int            fb_width;
-       unsigned int            fb_height;
-       unsigned int            bpp;
-       unsigned int            pixel_format;
-       dma_addr_t              dma_addr;
-       bool                    enabled;
-       bool                    resume;
-};
-
 struct decon_context {
        struct device                   *dev;
        struct drm_device               *drm_dev;
        struct exynos_drm_crtc          *crtc;
+       struct exynos_drm_plane         planes[WINDOWS_NR];
        struct clk                      *pclk;
        struct clk                      *aclk;
        struct clk                      *eclk;
        struct clk                      *vclk;
        void __iomem                    *regs;
-       struct decon_win_data           win_data[WINDOWS_NR];
        unsigned int                    default_win;
        unsigned long                   irq_flags;
        bool                            i80_if;
@@ -296,59 +281,16 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
        }
 }
 
-static void decon_win_mode_set(struct exynos_drm_crtc *crtc,
-                       struct exynos_drm_plane *plane)
-{
-       struct decon_context *ctx = crtc->ctx;
-       struct decon_win_data *win_data;
-       int win, padding;
-
-       if (!plane) {
-               DRM_ERROR("plane is NULL\n");
-               return;
-       }
-
-       win = plane->zpos;
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
-
-       if (win < 0 || win >= WINDOWS_NR)
-               return;
-
-
-       win_data = &ctx->win_data[win];
-
-       padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width;
-       win_data->offset_x = plane->fb_x;
-       win_data->offset_y = plane->fb_y;
-       win_data->fb_width = plane->fb_width + padding;
-       win_data->fb_height = plane->fb_height;
-       win_data->ovl_x = plane->crtc_x;
-       win_data->ovl_y = plane->crtc_y;
-       win_data->ovl_width = plane->crtc_width;
-       win_data->ovl_height = plane->crtc_height;
-       win_data->dma_addr = plane->dma_addr[0];
-       win_data->bpp = plane->bpp;
-       win_data->pixel_format = plane->pixel_format;
-
-       DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
-                       win_data->offset_x, win_data->offset_y);
-       DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
-                       win_data->ovl_width, win_data->ovl_height);
-       DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
-       DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
-                       plane->fb_width, plane->crtc_width);
-}
-
 static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
 {
-       struct decon_win_data *win_data = &ctx->win_data[win];
+       struct exynos_drm_plane *plane = &ctx->planes[win];
        unsigned long val;
+       int padding;
 
        val = readl(ctx->regs + WINCON(win));
        val &= ~WINCONx_BPPMODE_MASK;
 
-       switch (win_data->pixel_format) {
+       switch (plane->pixel_format) {
        case DRM_FORMAT_RGB565:
                val |= WINCONx_BPPMODE_16BPP_565;
                val |= WINCONx_BURSTLEN_16WORD;
@@ -397,7 +339,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
                break;
        }
 
-       DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp);
+       DRM_DEBUG_KMS("bpp = %d\n", plane->bpp);
 
        /*
         * In case of exynos, setting dma-burst to 16Word causes permanent
@@ -407,7 +349,8 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
         * movement causes unstable DMA which results into iommu crash/tear.
         */
 
-       if (win_data->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
+       padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width;
+       if (plane->fb_width + padding < MIN_FB_WIDTH_FOR_16WORD_BURST) {
                val &= ~WINCONx_BURSTLEN_MASK;
                val |= WINCONx_BURSTLEN_8WORD;
        }
@@ -435,7 +378,7 @@ static void decon_win_set_colkey(struct decon_context *ctx, unsigned int win)
  * @protect: 1 to protect (disable updates)
  */
 static void decon_shadow_protect_win(struct decon_context *ctx,
-                                                       int win, bool protect)
+                                    unsigned int win, bool protect)
 {
        u32 bits, val;
 
@@ -449,12 +392,12 @@ static void decon_shadow_protect_win(struct decon_context *ctx,
        writel(val, ctx->regs + SHADOWCON);
 }
 
-static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos)
+static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
 {
        struct decon_context *ctx = crtc->ctx;
        struct drm_display_mode *mode = &crtc->base.mode;
-       struct decon_win_data *win_data;
-       int win = zpos;
+       struct exynos_drm_plane *plane;
+       int padding;
        unsigned long val, alpha;
        unsigned int last_x;
        unsigned int last_y;
@@ -462,17 +405,14 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos)
        if (ctx->suspended)
                return;
 
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
-
        if (win < 0 || win >= WINDOWS_NR)
                return;
 
-       win_data = &ctx->win_data[win];
+       plane = &ctx->planes[win];
 
        /* If suspended, enable this on resume */
        if (ctx->suspended) {
-               win_data->resume = true;
+               plane->resume = true;
                return;
        }
 
@@ -490,39 +430,41 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos)
        decon_shadow_protect_win(ctx, win, true);
 
        /* buffer start address */
-       val = (unsigned long)win_data->dma_addr;
+       val = (unsigned long)plane->dma_addr[0];
        writel(val, ctx->regs + VIDW_BUF_START(win));
 
+       padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width;
+
        /* buffer size */
-       writel(win_data->fb_width, ctx->regs + VIDW_WHOLE_X(win));
-       writel(win_data->fb_height, ctx->regs + VIDW_WHOLE_Y(win));
+       writel(plane->fb_width + padding, ctx->regs + VIDW_WHOLE_X(win));
+       writel(plane->fb_height, ctx->regs + VIDW_WHOLE_Y(win));
 
        /* offset from the start of the buffer to read */
-       writel(win_data->offset_x, ctx->regs + VIDW_OFFSET_X(win));
-       writel(win_data->offset_y, ctx->regs + VIDW_OFFSET_Y(win));
+       writel(plane->src_x, ctx->regs + VIDW_OFFSET_X(win));
+       writel(plane->src_y, ctx->regs + VIDW_OFFSET_Y(win));
 
        DRM_DEBUG_KMS("start addr = 0x%lx\n",
-                       (unsigned long)win_data->dma_addr);
+                       (unsigned long)val);
        DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
-                       win_data->ovl_width, win_data->ovl_height);
+                       plane->crtc_width, plane->crtc_height);
 
        /*
         * OSD position.
         * In case the window layout goes of LCD layout, DECON fails.
         */
-       if ((win_data->ovl_x + win_data->ovl_width) > mode->hdisplay)
-               win_data->ovl_x = mode->hdisplay - win_data->ovl_width;
-       if ((win_data->ovl_y + win_data->ovl_height) > mode->vdisplay)
-               win_data->ovl_y = mode->vdisplay - win_data->ovl_height;
+       if ((plane->crtc_x + plane->crtc_width) > mode->hdisplay)
+               plane->crtc_x = mode->hdisplay - plane->crtc_width;
+       if ((plane->crtc_y + plane->crtc_height) > mode->vdisplay)
+               plane->crtc_y = mode->vdisplay - plane->crtc_height;
 
-       val = VIDOSDxA_TOPLEFT_X(win_data->ovl_x) |
-               VIDOSDxA_TOPLEFT_Y(win_data->ovl_y);
+       val = VIDOSDxA_TOPLEFT_X(plane->crtc_x) |
+               VIDOSDxA_TOPLEFT_Y(plane->crtc_y);
        writel(val, ctx->regs + VIDOSD_A(win));
 
-       last_x = win_data->ovl_x + win_data->ovl_width;
+       last_x = plane->crtc_x + plane->crtc_width;
        if (last_x)
                last_x--;
-       last_y = win_data->ovl_y + win_data->ovl_height;
+       last_y = plane->crtc_y + plane->crtc_height;
        if (last_y)
                last_y--;
 
@@ -531,7 +473,7 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos)
        writel(val, ctx->regs + VIDOSD_B(win));
 
        DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
-                       win_data->ovl_x, win_data->ovl_y, last_x, last_y);
+                       plane->crtc_x, plane->crtc_y, last_x, last_y);
 
        /* OSD alpha */
        alpha = VIDOSDxC_ALPHA0_R_F(0x0) |
@@ -565,27 +507,23 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos)
        val |= DECON_UPDATE_STANDALONE_F;
        writel(val, ctx->regs + DECON_UPDATE);
 
-       win_data->enabled = true;
+       plane->enabled = true;
 }
 
-static void decon_win_disable(struct exynos_drm_crtc *crtc, int zpos)
+static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
 {
        struct decon_context *ctx = crtc->ctx;
-       struct decon_win_data *win_data;
-       int win = zpos;
+       struct exynos_drm_plane *plane;
        u32 val;
 
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
-
        if (win < 0 || win >= WINDOWS_NR)
                return;
 
-       win_data = &ctx->win_data[win];
+       plane = &ctx->planes[win];
 
        if (ctx->suspended) {
                /* do not resume this window*/
-               win_data->resume = false;
+               plane->resume = false;
                return;
        }
 
@@ -604,42 +542,42 @@ static void decon_win_disable(struct exynos_drm_crtc *crtc, int zpos)
        val |= DECON_UPDATE_STANDALONE_F;
        writel(val, ctx->regs + DECON_UPDATE);
 
-       win_data->enabled = false;
+       plane->enabled = false;
 }
 
 static void decon_window_suspend(struct decon_context *ctx)
 {
-       struct decon_win_data *win_data;
+       struct exynos_drm_plane *plane;
        int i;
 
        for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               win_data->resume = win_data->enabled;
-               if (win_data->enabled)
+               plane = &ctx->planes[i];
+               plane->resume = plane->enabled;
+               if (plane->enabled)
                        decon_win_disable(ctx->crtc, i);
        }
 }
 
 static void decon_window_resume(struct decon_context *ctx)
 {
-       struct decon_win_data *win_data;
+       struct exynos_drm_plane *plane;
        int i;
 
        for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               win_data->enabled = win_data->resume;
-               win_data->resume = false;
+               plane = &ctx->planes[i];
+               plane->enabled = plane->resume;
+               plane->resume = false;
        }
 }
 
 static void decon_apply(struct decon_context *ctx)
 {
-       struct decon_win_data *win_data;
+       struct exynos_drm_plane *plane;
        int i;
 
        for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               if (win_data->enabled)
+               plane = &ctx->planes[i];
+               if (plane->enabled)
                        decon_win_commit(ctx->crtc, i);
                else
                        decon_win_disable(ctx->crtc, i);
@@ -779,7 +717,6 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = {
        .enable_vblank = decon_enable_vblank,
        .disable_vblank = decon_disable_vblank,
        .wait_for_vblank = decon_wait_for_vblank,
-       .win_mode_set = decon_win_mode_set,
        .win_commit = decon_win_commit,
        .win_disable = decon_win_disable,
 };
@@ -818,6 +755,9 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
 {
        struct decon_context *ctx = dev_get_drvdata(dev);
        struct drm_device *drm_dev = data;
+       struct exynos_drm_plane *exynos_plane;
+       enum drm_plane_type type;
+       unsigned int zpos;
        int ret;
 
        ret = decon_ctx_initialize(ctx, drm_dev);
@@ -826,8 +766,18 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
                return ret;
        }
 
-       ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
-                                          EXYNOS_DISPLAY_TYPE_LCD,
+       for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
+               type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
+                                               DRM_PLANE_TYPE_OVERLAY;
+               ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
+                                       1 << ctx->pipe, type, zpos);
+               if (ret)
+                       return ret;
+       }
+
+       exynos_plane = &ctx->planes[ctx->default_win];
+       ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
+                                          ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD,
                                           &decon_crtc_ops, ctx);
        if (IS_ERR(ctx->crtc)) {
                decon_ctx_remove(ctx);
index bf17a60b40edc88e77c2c3330c0f7dc3adee7295..1dbfba58f9091b70aac969a55e270d844ea5fb05 100644 (file)
 #include <drm/bridge/ptn3460.h>
 
 #include "exynos_dp_core.h"
+#include "exynos_drm_fimd.h"
 
 #define ctx_from_connector(c)  container_of(c, struct exynos_dp_device, \
                                        connector)
 
+static inline struct exynos_drm_crtc *dp_to_crtc(struct exynos_dp_device *dp)
+{
+       return to_exynos_crtc(dp->encoder->crtc);
+}
+
 static inline struct exynos_dp_device *
 display_to_dp(struct exynos_drm_display *d)
 {
@@ -1070,6 +1076,8 @@ static void exynos_dp_poweron(struct exynos_dp_device *dp)
                }
        }
 
+       fimd_dp_clock_enable(dp_to_crtc(dp), true);
+
        clk_prepare_enable(dp->clock);
        exynos_dp_phy_init(dp);
        exynos_dp_init_dp(dp);
@@ -1094,6 +1102,8 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp)
        exynos_dp_phy_exit(dp);
        clk_disable_unprepare(dp->clock);
 
+       fimd_dp_clock_enable(dp_to_crtc(dp), false);
+
        if (dp->panel) {
                if (drm_panel_unprepare(dp->panel))
                        DRM_ERROR("failed to turnoff the panel\n");
index 48ccab7fdf63e51888b422d7dd8175c66bda440d..eb49195cec5c2396831ebfbf37e42bb5fa54ed81 100644 (file)
@@ -34,9 +34,8 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
        if (mode > DRM_MODE_DPMS_ON) {
                /* wait for the completion of page flip. */
                if (!wait_event_timeout(exynos_crtc->pending_flip_queue,
-                               !atomic_read(&exynos_crtc->pending_flip),
-                               HZ/20))
-                       atomic_set(&exynos_crtc->pending_flip, 0);
+                               (exynos_crtc->event == NULL), HZ/20))
+                       exynos_crtc->event = NULL;
                drm_crtc_vblank_off(crtc);
        }
 
@@ -164,11 +163,10 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
                                     uint32_t page_flip_flags)
 {
        struct drm_device *dev = crtc->dev;
-       struct exynos_drm_private *dev_priv = dev->dev_private;
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
        struct drm_framebuffer *old_fb = crtc->primary->fb;
        unsigned int crtc_w, crtc_h;
-       int ret = -EINVAL;
+       int ret;
 
        /* when the page flip is requested, crtc's dpms should be on */
        if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) {
@@ -176,48 +174,49 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
                return -EINVAL;
        }
 
-       mutex_lock(&dev->struct_mutex);
+       if (!event)
+               return -EINVAL;
 
-       if (event) {
-               /*
-                * the pipe from user always is 0 so we can set pipe number
-                * of current owner to event.
-                */
-               event->pipe = exynos_crtc->pipe;
+       spin_lock_irq(&dev->event_lock);
+       if (exynos_crtc->event) {
+               ret = -EBUSY;
+               goto out;
+       }
 
-               ret = drm_vblank_get(dev, exynos_crtc->pipe);
-               if (ret) {
-                       DRM_DEBUG("failed to acquire vblank counter\n");
+       ret = drm_vblank_get(dev, exynos_crtc->pipe);
+       if (ret) {
+               DRM_DEBUG("failed to acquire vblank counter\n");
+               goto out;
+       }
 
-                       goto out;
-               }
+       exynos_crtc->event = event;
+       spin_unlock_irq(&dev->event_lock);
 
+       /*
+        * the pipe from user always is 0 so we can set pipe number
+        * of current owner to event.
+        */
+       event->pipe = exynos_crtc->pipe;
+
+       crtc->primary->fb = fb;
+       crtc_w = fb->width - crtc->x;
+       crtc_h = fb->height - crtc->y;
+       ret = exynos_update_plane(crtc->primary, crtc, fb, 0, 0,
+                                 crtc_w, crtc_h, crtc->x, crtc->y,
+                                 crtc_w, crtc_h);
+       if (ret) {
+               crtc->primary->fb = old_fb;
                spin_lock_irq(&dev->event_lock);
-               list_add_tail(&event->base.link,
-                               &dev_priv->pageflip_event_list);
-               atomic_set(&exynos_crtc->pending_flip, 1);
+               exynos_crtc->event = NULL;
+               drm_vblank_put(dev, exynos_crtc->pipe);
                spin_unlock_irq(&dev->event_lock);
-
-               crtc->primary->fb = fb;
-               crtc_w = fb->width - crtc->x;
-               crtc_h = fb->height - crtc->y;
-               ret = exynos_update_plane(crtc->primary, crtc, fb, 0, 0,
-                                         crtc_w, crtc_h, crtc->x, crtc->y,
-                                         crtc_w, crtc_h);
-               if (ret) {
-                       crtc->primary->fb = old_fb;
-
-                       spin_lock_irq(&dev->event_lock);
-                       drm_vblank_put(dev, exynos_crtc->pipe);
-                       list_del(&event->base.link);
-                       atomic_set(&exynos_crtc->pending_flip, 0);
-                       spin_unlock_irq(&dev->event_lock);
-
-                       goto out;
-               }
+               return ret;
        }
+
+       return 0;
+
 out:
-       mutex_unlock(&dev->struct_mutex);
+       spin_unlock_irq(&dev->event_lock);
        return ret;
 }
 
@@ -239,13 +238,13 @@ static struct drm_crtc_funcs exynos_crtc_funcs = {
 };
 
 struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
+                                              struct drm_plane *plane,
                                               int pipe,
                                               enum exynos_drm_output_type type,
                                               struct exynos_drm_crtc_ops *ops,
                                               void *ctx)
 {
        struct exynos_drm_crtc *exynos_crtc;
-       struct drm_plane *plane;
        struct exynos_drm_private *private = drm_dev->dev_private;
        struct drm_crtc *crtc;
        int ret;
@@ -255,19 +254,12 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
                return ERR_PTR(-ENOMEM);
 
        init_waitqueue_head(&exynos_crtc->pending_flip_queue);
-       atomic_set(&exynos_crtc->pending_flip, 0);
 
        exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
        exynos_crtc->pipe = pipe;
        exynos_crtc->type = type;
        exynos_crtc->ops = ops;
        exynos_crtc->ctx = ctx;
-       plane = exynos_plane_init(drm_dev, 1 << pipe,
-                                 DRM_PLANE_TYPE_PRIMARY);
-       if (IS_ERR(plane)) {
-               ret = PTR_ERR(plane);
-               goto err_plane;
-       }
 
        crtc = &exynos_crtc->base;
 
@@ -284,7 +276,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
 
 err_crtc:
        plane->funcs->destroy(plane);
-err_plane:
        kfree(exynos_crtc);
        return ERR_PTR(ret);
 }
@@ -320,26 +311,20 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
 void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe)
 {
        struct exynos_drm_private *dev_priv = dev->dev_private;
-       struct drm_pending_vblank_event *e, *t;
        struct drm_crtc *drm_crtc = dev_priv->crtc[pipe];
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc);
        unsigned long flags;
 
        spin_lock_irqsave(&dev->event_lock, flags);
+       if (exynos_crtc->event) {
 
-       list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
-                       base.link) {
-               /* if event's pipe isn't same as crtc then ignore it. */
-               if (pipe != e->pipe)
-                       continue;
-
-               list_del(&e->base.link);
-               drm_send_vblank_event(dev, -1, e);
+               drm_send_vblank_event(dev, -1, exynos_crtc->event);
                drm_vblank_put(dev, pipe);
-               atomic_set(&exynos_crtc->pending_flip, 0);
                wake_up(&exynos_crtc->pending_flip_queue);
+
        }
 
+       exynos_crtc->event = NULL;
        spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
index 6258b800aab80d199f1257a9794d8b643bac3b69..0ecd8fc45cff3349afe5d5858a713da124e30944 100644 (file)
@@ -18,6 +18,7 @@
 #include "exynos_drm_drv.h"
 
 struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
+                                              struct drm_plane *plane,
                                               int pipe,
                                               enum exynos_drm_output_type type,
                                               struct exynos_drm_crtc_ops *ops,
@@ -27,12 +28,6 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe);
 void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe);
 void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb);
 
-void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
-                       struct exynos_drm_plane *plane);
-void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos);
-void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos);
-void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos);
-
 /* This function gets pipe value to crtc device matched with out_type. */
 int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
                                        unsigned int out_type);
index 90168d7cf66a4e9741555e0aa6a51e45e16ac1ba..8ac465208eae1df44a10aac219e27a3ee683806d 100644 (file)
@@ -55,13 +55,11 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 {
        struct exynos_drm_private *private;
        int ret;
-       int nr;
 
        private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL);
        if (!private)
                return -ENOMEM;
 
-       INIT_LIST_HEAD(&private->pageflip_event_list);
        dev_set_drvdata(dev->dev, dev);
        dev->dev_private = (void *)private;
 
@@ -81,19 +79,6 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 
        exynos_drm_mode_config_init(dev);
 
-       for (nr = 0; nr < MAX_PLANE; nr++) {
-               struct drm_plane *plane;
-               unsigned long possible_crtcs = (1 << MAX_CRTC) - 1;
-
-               plane = exynos_plane_init(dev, possible_crtcs,
-                                         DRM_PLANE_TYPE_OVERLAY);
-               if (!IS_ERR(plane))
-                       continue;
-
-               ret = PTR_ERR(plane);
-               goto err_mode_config_cleanup;
-       }
-
        /* setup possible_clones. */
        exynos_drm_encoder_setup(dev);
 
@@ -237,25 +222,13 @@ static void exynos_drm_preclose(struct drm_device *dev,
 
 static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
 {
-       struct exynos_drm_private *private = dev->dev_private;
-       struct drm_pending_vblank_event *v, *vt;
        struct drm_pending_event *e, *et;
        unsigned long flags;
 
        if (!file->driver_priv)
                return;
 
-       /* Release all events not unhandled by page flip handler. */
        spin_lock_irqsave(&dev->event_lock, flags);
-       list_for_each_entry_safe(v, vt, &private->pageflip_event_list,
-                       base.link) {
-               if (v->base.file_priv == file) {
-                       list_del(&v->base.link);
-                       drm_vblank_put(dev, v->pipe);
-                       v->base.destroy(&v->base);
-               }
-       }
-
        /* Release all events handled by page flip handler but not freed. */
        list_for_each_entry_safe(e, et, &file->event_list, link) {
                list_del(&e->link);
index 9afd390d4674d81ff28fb6e7ab5adcba2b8d8b37..e12ecb5d5d9aa01a7618eafb8930b5dc552cb14e 100644 (file)
@@ -21,7 +21,6 @@
 #define MAX_CRTC       3
 #define MAX_PLANE      5
 #define MAX_FB_BUFFER  4
-#define DEFAULT_ZPOS   -1
 
 #define to_exynos_crtc(x)      container_of(x, struct exynos_drm_crtc, base)
 #define to_exynos_plane(x)     container_of(x, struct exynos_drm_plane, base)
@@ -48,20 +47,22 @@ enum exynos_drm_output_type {
  * Exynos drm common overlay structure.
  *
  * @base: plane object
- * @fb_x: offset x on a framebuffer to be displayed.
+ * @src_x: offset x on a framebuffer to be displayed.
  *     - the unit is screen coordinates.
- * @fb_y: offset y on a framebuffer to be displayed.
+ * @src_y: offset y on a framebuffer to be displayed.
  *     - the unit is screen coordinates.
- * @fb_width: width of a framebuffer.
- * @fb_height: height of a framebuffer.
  * @src_width: width of a partial image to be displayed from framebuffer.
  * @src_height: height of a partial image to be displayed from framebuffer.
+ * @fb_width: width of a framebuffer.
+ * @fb_height: height of a framebuffer.
  * @crtc_x: offset x on hardware screen.
  * @crtc_y: offset y on hardware screen.
  * @crtc_width: window width to be displayed (hardware screen).
  * @crtc_height: window height to be displayed (hardware screen).
  * @mode_width: width of screen mode.
  * @mode_height: height of screen mode.
+ * @h_ratio: horizontal scaling ratio, 16.16 fixed point
+ * @v_ratio: vertical scaling ratio, 16.16 fixed point
  * @refresh: refresh rate.
  * @scan_flag: interlace or progressive way.
  *     (it could be DRM_MODE_FLAG_*)
@@ -78,6 +79,7 @@ enum exynos_drm_output_type {
  * @transparency: transparency on or off.
  * @activated: activated or not.
  * @enabled: enabled or not.
+ * @resume: to resume or not.
  *
  * this structure is common to exynos SoC and its contents would be copied
  * to hardware specific overlay info.
@@ -85,25 +87,27 @@ enum exynos_drm_output_type {
 
 struct exynos_drm_plane {
        struct drm_plane base;
-       unsigned int fb_x;
-       unsigned int fb_y;
-       unsigned int fb_width;
-       unsigned int fb_height;
+       unsigned int src_x;
+       unsigned int src_y;
        unsigned int src_width;
        unsigned int src_height;
+       unsigned int fb_width;
+       unsigned int fb_height;
        unsigned int crtc_x;
        unsigned int crtc_y;
        unsigned int crtc_width;
        unsigned int crtc_height;
        unsigned int mode_width;
        unsigned int mode_height;
+       unsigned int h_ratio;
+       unsigned int v_ratio;
        unsigned int refresh;
        unsigned int scan_flag;
        unsigned int bpp;
        unsigned int pitch;
        uint32_t pixel_format;
        dma_addr_t dma_addr[MAX_FB_BUFFER];
-       int zpos;
+       unsigned int zpos;
        unsigned int index_color;
 
        bool default_win:1;
@@ -112,6 +116,7 @@ struct exynos_drm_plane {
        bool transparency:1;
        bool activated:1;
        bool enabled:1;
+       bool resume:1;
 };
 
 /*
@@ -172,9 +177,7 @@ struct exynos_drm_display {
  * @disable_vblank: specific driver callback for disabling vblank interrupt.
  * @wait_for_vblank: wait for vblank interrupt to make sure that
  *     hardware overlay is updated.
- * @win_mode_set: copy drm overlay info to hw specific overlay info.
  * @win_commit: apply hardware specific overlay data to registers.
- * @win_enable: enable hardware specific overlay.
  * @win_disable: disable hardware specific overlay.
  * @te_handler: trigger to transfer video image at the tearing effect
  *     synchronization signal if there is a page flip request.
@@ -189,11 +192,8 @@ struct exynos_drm_crtc_ops {
        int (*enable_vblank)(struct exynos_drm_crtc *crtc);
        void (*disable_vblank)(struct exynos_drm_crtc *crtc);
        void (*wait_for_vblank)(struct exynos_drm_crtc *crtc);
-       void (*win_mode_set)(struct exynos_drm_crtc *crtc,
-                               struct exynos_drm_plane *plane);
-       void (*win_commit)(struct exynos_drm_crtc *crtc, int zpos);
-       void (*win_enable)(struct exynos_drm_crtc *crtc, int zpos);
-       void (*win_disable)(struct exynos_drm_crtc *crtc, int zpos);
+       void (*win_commit)(struct exynos_drm_crtc *crtc, unsigned int zpos);
+       void (*win_disable)(struct exynos_drm_crtc *crtc, unsigned int zpos);
        void (*te_handler)(struct exynos_drm_crtc *crtc);
 };
 
@@ -210,6 +210,7 @@ struct exynos_drm_crtc_ops {
  *     we can refer to the crtc to current hardware interrupt occurred through
  *     this pipe value.
  * @dpms: store the crtc dpms value
+ * @event: vblank event that is currently queued for flip
  * @ops: pointer to callbacks for exynos drm specific functionality
  * @ctx: A pointer to the crtc's implementation specific context
  */
@@ -219,7 +220,7 @@ struct exynos_drm_crtc {
        unsigned int                    pipe;
        unsigned int                    dpms;
        wait_queue_head_t               pending_flip_queue;
-       atomic_t                        pending_flip;
+       struct drm_pending_vblank_event *event;
        struct exynos_drm_crtc_ops      *ops;
        void                            *ctx;
 };
@@ -249,9 +250,6 @@ struct drm_exynos_file_private {
 struct exynos_drm_private {
        struct drm_fb_helper *fb_helper;
 
-       /* list head for new event to be added. */
-       struct list_head pageflip_event_list;
-
        /*
         * created crtc object would be contained at this array and
         * this array is used to be aware of which crtc did it request vblank.
index 05fe93dc57a8bccdd14b6db9cb40f9ef99944619..04927153bf38dedcd70546ec3e41b2159c72083e 100644 (file)
@@ -1473,12 +1473,6 @@ static int exynos_dsi_get_modes(struct drm_connector *connector)
        return 0;
 }
 
-static int exynos_dsi_mode_valid(struct drm_connector *connector,
-                                struct drm_display_mode *mode)
-{
-       return MODE_OK;
-}
-
 static struct drm_encoder *
 exynos_dsi_best_encoder(struct drm_connector *connector)
 {
@@ -1489,7 +1483,6 @@ exynos_dsi_best_encoder(struct drm_connector *connector)
 
 static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
        .get_modes = exynos_dsi_get_modes,
-       .mode_valid = exynos_dsi_mode_valid,
        .best_encoder = exynos_dsi_best_encoder,
 };
 
index d346d1e6eda03775e63d6ad7f969a1e1a9f4431d..929cb03a8eab15d6daee766016dc59070130a240 100644 (file)
@@ -151,10 +151,8 @@ exynos_drm_framebuffer_init(struct drm_device *dev,
        exynos_gem_obj = to_exynos_gem_obj(obj);
 
        ret = check_fb_gem_memory_type(dev, exynos_gem_obj);
-       if (ret < 0) {
-               DRM_ERROR("cannot use this gem memory type for fb.\n");
-               return ERR_PTR(-EINVAL);
-       }
+       if (ret < 0)
+               return ERR_PTR(ret);
 
        exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);
        if (!exynos_fb)
@@ -250,10 +248,8 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
                exynos_fb->exynos_gem_obj[i] = exynos_gem_obj;
 
                ret = check_fb_gem_memory_type(dev, exynos_gem_obj);
-               if (ret < 0) {
-                       DRM_ERROR("cannot use this gem memory type for fb.\n");
+               if (ret < 0)
                        goto err_unreference;
-               }
        }
 
        ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs);
index 84f8dfe1c5ec02ec383b0d74cf615b7906388d9a..e71e331f0188c009f56bffe1fa81b2ec0be29164 100644 (file)
@@ -76,6 +76,7 @@ static struct fb_ops exynos_drm_fb_ops = {
 };
 
 static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
+                                    struct drm_fb_helper_surface_size *sizes,
                                     struct drm_framebuffer *fb)
 {
        struct fb_info *fbi = helper->fbdev;
@@ -85,7 +86,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
        unsigned long offset;
 
        drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
-       drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
+       drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
 
        /* RGB formats use only one buffer */
        buffer = exynos_drm_fb_buffer(fb, 0);
@@ -189,7 +190,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
                goto err_destroy_framebuffer;
        }
 
-       ret = exynos_drm_fbdev_update(helper, helper->fb);
+       ret = exynos_drm_fbdev_update(helper, sizes, helper->fb);
        if (ret < 0)
                goto err_dealloc_cmap;
 
index c300e22da8ac5f2f4294c27543e62291ee0a8739..9819fa6a9e2a41867da1ddaab9fb052dc0a74310 100644 (file)
@@ -31,7 +31,9 @@
 #include "exynos_drm_drv.h"
 #include "exynos_drm_fbdev.h"
 #include "exynos_drm_crtc.h"
+#include "exynos_drm_plane.h"
 #include "exynos_drm_iommu.h"
+#include "exynos_drm_fimd.h"
 
 /*
  * FIMD stands for Fully Interactive Mobile Display and
@@ -54,6 +56,9 @@
 /* size control register for hardware windows 1 ~ 2. */
 #define VIDOSD_D(win)          (VIDOSD_BASE + 0x0C + (win) * 16)
 
+#define VIDWnALPHA0(win)       (VIDW_ALPHA + 0x00 + (win) * 8)
+#define VIDWnALPHA1(win)       (VIDW_ALPHA + 0x04 + (win) * 8)
+
 #define VIDWx_BUF_START(win, buf)      (VIDW_BUF_START(buf) + (win) * 8)
 #define VIDWx_BUF_END(win, buf)                (VIDW_BUF_END(buf) + (win) * 8)
 #define VIDWx_BUF_SIZE(win, buf)       (VIDW_BUF_SIZE(buf) + (win) * 4)
@@ -140,31 +145,15 @@ static struct fimd_driver_data exynos5_fimd_driver_data = {
        .has_vtsel = 1,
 };
 
-struct fimd_win_data {
-       unsigned int            offset_x;
-       unsigned int            offset_y;
-       unsigned int            ovl_width;
-       unsigned int            ovl_height;
-       unsigned int            fb_width;
-       unsigned int            fb_height;
-       unsigned int            bpp;
-       unsigned int            pixel_format;
-       dma_addr_t              dma_addr;
-       unsigned int            buf_offsize;
-       unsigned int            line_size;      /* bytes */
-       bool                    enabled;
-       bool                    resume;
-};
-
 struct fimd_context {
        struct device                   *dev;
        struct drm_device               *drm_dev;
        struct exynos_drm_crtc          *crtc;
+       struct exynos_drm_plane         planes[WINDOWS_NR];
        struct clk                      *bus_clk;
        struct clk                      *lcd_clk;
        void __iomem                    *regs;
        struct regmap                   *sysreg;
-       struct fimd_win_data            win_data[WINDOWS_NR];
        unsigned int                    default_win;
        unsigned long                   irq_flags;
        u32                             vidcon0;
@@ -501,58 +490,9 @@ static void fimd_disable_vblank(struct exynos_drm_crtc *crtc)
        }
 }
 
-static void fimd_win_mode_set(struct exynos_drm_crtc *crtc,
-                       struct exynos_drm_plane *plane)
-{
-       struct fimd_context *ctx = crtc->ctx;
-       struct fimd_win_data *win_data;
-       int win;
-       unsigned long offset;
-
-       if (!plane) {
-               DRM_ERROR("plane is NULL\n");
-               return;
-       }
-
-       win = plane->zpos;
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
-
-       if (win < 0 || win >= WINDOWS_NR)
-               return;
-
-       offset = plane->fb_x * (plane->bpp >> 3);
-       offset += plane->fb_y * plane->pitch;
-
-       DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, plane->pitch);
-
-       win_data = &ctx->win_data[win];
-
-       win_data->offset_x = plane->crtc_x;
-       win_data->offset_y = plane->crtc_y;
-       win_data->ovl_width = plane->crtc_width;
-       win_data->ovl_height = plane->crtc_height;
-       win_data->fb_width = plane->fb_width;
-       win_data->fb_height = plane->fb_height;
-       win_data->dma_addr = plane->dma_addr[0] + offset;
-       win_data->bpp = plane->bpp;
-       win_data->pixel_format = plane->pixel_format;
-       win_data->buf_offsize = (plane->fb_width - plane->crtc_width) *
-                               (plane->bpp >> 3);
-       win_data->line_size = plane->crtc_width * (plane->bpp >> 3);
-
-       DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
-                       win_data->offset_x, win_data->offset_y);
-       DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
-                       win_data->ovl_width, win_data->ovl_height);
-       DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
-       DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
-                       plane->fb_width, plane->crtc_width);
-}
-
 static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
 {
-       struct fimd_win_data *win_data = &ctx->win_data[win];
+       struct exynos_drm_plane *plane = &ctx->planes[win];
        unsigned long val;
 
        val = WINCONx_ENWIN;
@@ -562,11 +502,11 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
         * So the request format is ARGB8888 then change it to XRGB8888.
         */
        if (ctx->driver_data->has_limited_fmt && !win) {
-               if (win_data->pixel_format == DRM_FORMAT_ARGB8888)
-                       win_data->pixel_format = DRM_FORMAT_XRGB8888;
+               if (plane->pixel_format == DRM_FORMAT_ARGB8888)
+                       plane->pixel_format = DRM_FORMAT_XRGB8888;
        }
 
-       switch (win_data->pixel_format) {
+       switch (plane->pixel_format) {
        case DRM_FORMAT_C8:
                val |= WINCON0_BPPMODE_8BPP_PALETTE;
                val |= WINCONx_BURSTLEN_8WORD;
@@ -602,7 +542,7 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
                break;
        }
 
-       DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp);
+       DRM_DEBUG_KMS("bpp = %d\n", plane->bpp);
 
        /*
         * In case of exynos, setting dma-burst to 16Word causes permanent
@@ -612,12 +552,30 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
         * movement causes unstable DMA which results into iommu crash/tear.
         */
 
-       if (win_data->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
+       if (plane->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
                val &= ~WINCONx_BURSTLEN_MASK;
                val |= WINCONx_BURSTLEN_4WORD;
        }
 
        writel(val, ctx->regs + WINCON(win));
+
+       /* hardware window 0 doesn't support alpha channel. */
+       if (win != 0) {
+               /* OSD alpha */
+               val = VIDISD14C_ALPHA0_R(0xf) |
+                       VIDISD14C_ALPHA0_G(0xf) |
+                       VIDISD14C_ALPHA0_B(0xf) |
+                       VIDISD14C_ALPHA1_R(0xf) |
+                       VIDISD14C_ALPHA1_G(0xf) |
+                       VIDISD14C_ALPHA1_B(0xf);
+
+               writel(val, ctx->regs + VIDOSD_C(win));
+
+               val = VIDW_ALPHA_R(0xf) | VIDW_ALPHA_G(0xf) |
+                       VIDW_ALPHA_G(0xf);
+               writel(val, ctx->regs + VIDWnALPHA0(win));
+               writel(val, ctx->regs + VIDWnALPHA1(win));
+       }
 }
 
 static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int win)
@@ -640,7 +598,7 @@ static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int win)
  * @protect: 1 to protect (disable updates)
  */
 static void fimd_shadow_protect_win(struct fimd_context *ctx,
-                                                       int win, bool protect)
+                                   unsigned int win, bool protect)
 {
        u32 reg, bits, val;
 
@@ -660,29 +618,25 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx,
        writel(val, ctx->regs + reg);
 }
 
-static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos)
+static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
 {
        struct fimd_context *ctx = crtc->ctx;
-       struct fimd_win_data *win_data;
-       int win = zpos;
-       unsigned long val, alpha, size;
-       unsigned int last_x;
-       unsigned int last_y;
+       struct exynos_drm_plane *plane;
+       dma_addr_t dma_addr;
+       unsigned long val, size, offset;
+       unsigned int last_x, last_y, buf_offsize, line_size;
 
        if (ctx->suspended)
                return;
 
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
-
        if (win < 0 || win >= WINDOWS_NR)
                return;
 
-       win_data = &ctx->win_data[win];
+       plane = &ctx->planes[win];
 
        /* If suspended, enable this on resume */
        if (ctx->suspended) {
-               win_data->resume = true;
+               plane->resume = true;
                return;
        }
 
@@ -699,38 +653,45 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos)
        /* protect windows */
        fimd_shadow_protect_win(ctx, win, true);
 
+
+       offset = plane->src_x * (plane->bpp >> 3);
+       offset += plane->src_y * plane->pitch;
+
        /* buffer start address */
-       val = (unsigned long)win_data->dma_addr;
+       dma_addr = plane->dma_addr[0] + offset;
+       val = (unsigned long)dma_addr;
        writel(val, ctx->regs + VIDWx_BUF_START(win, 0));
 
        /* buffer end address */
-       size = win_data->fb_width * win_data->ovl_height * (win_data->bpp >> 3);
-       val = (unsigned long)(win_data->dma_addr + size);
+       size = plane->pitch * plane->crtc_height;
+       val = (unsigned long)(dma_addr + size);
        writel(val, ctx->regs + VIDWx_BUF_END(win, 0));
 
        DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n",
-                       (unsigned long)win_data->dma_addr, val, size);
+                       (unsigned long)dma_addr, val, size);
        DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
-                       win_data->ovl_width, win_data->ovl_height);
+                       plane->crtc_width, plane->crtc_height);
 
        /* buffer size */
-       val = VIDW_BUF_SIZE_OFFSET(win_data->buf_offsize) |
-               VIDW_BUF_SIZE_PAGEWIDTH(win_data->line_size) |
-               VIDW_BUF_SIZE_OFFSET_E(win_data->buf_offsize) |
-               VIDW_BUF_SIZE_PAGEWIDTH_E(win_data->line_size);
+       buf_offsize = plane->pitch - (plane->crtc_width * (plane->bpp >> 3));
+       line_size = plane->crtc_width * (plane->bpp >> 3);
+       val = VIDW_BUF_SIZE_OFFSET(buf_offsize) |
+               VIDW_BUF_SIZE_PAGEWIDTH(line_size) |
+               VIDW_BUF_SIZE_OFFSET_E(buf_offsize) |
+               VIDW_BUF_SIZE_PAGEWIDTH_E(line_size);
        writel(val, ctx->regs + VIDWx_BUF_SIZE(win, 0));
 
        /* OSD position */
-       val = VIDOSDxA_TOPLEFT_X(win_data->offset_x) |
-               VIDOSDxA_TOPLEFT_Y(win_data->offset_y) |
-               VIDOSDxA_TOPLEFT_X_E(win_data->offset_x) |
-               VIDOSDxA_TOPLEFT_Y_E(win_data->offset_y);
+       val = VIDOSDxA_TOPLEFT_X(plane->crtc_x) |
+               VIDOSDxA_TOPLEFT_Y(plane->crtc_y) |
+               VIDOSDxA_TOPLEFT_X_E(plane->crtc_x) |
+               VIDOSDxA_TOPLEFT_Y_E(plane->crtc_y);
        writel(val, ctx->regs + VIDOSD_A(win));
 
-       last_x = win_data->offset_x + win_data->ovl_width;
+       last_x = plane->crtc_x + plane->crtc_width;
        if (last_x)
                last_x--;
-       last_y = win_data->offset_y + win_data->ovl_height;
+       last_y = plane->crtc_y + plane->crtc_height;
        if (last_y)
                last_y--;
 
@@ -740,24 +701,14 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos)
        writel(val, ctx->regs + VIDOSD_B(win));
 
        DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
-                       win_data->offset_x, win_data->offset_y, last_x, last_y);
-
-       /* hardware window 0 doesn't support alpha channel. */
-       if (win != 0) {
-               /* OSD alpha */
-               alpha = VIDISD14C_ALPHA1_R(0xf) |
-                       VIDISD14C_ALPHA1_G(0xf) |
-                       VIDISD14C_ALPHA1_B(0xf);
-
-               writel(alpha, ctx->regs + VIDOSD_C(win));
-       }
+                       plane->crtc_x, plane->crtc_y, last_x, last_y);
 
        /* OSD size */
        if (win != 3 && win != 4) {
                u32 offset = VIDOSD_D(win);
                if (win == 0)
                        offset = VIDOSD_C(win);
-               val = win_data->ovl_width * win_data->ovl_height;
+               val = plane->crtc_width * plane->crtc_height;
                writel(val, ctx->regs + offset);
 
                DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
@@ -777,29 +728,25 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos)
        /* Enable DMA channel and unprotect windows */
        fimd_shadow_protect_win(ctx, win, false);
 
-       win_data->enabled = true;
+       plane->enabled = true;
 
        if (ctx->i80_if)
                atomic_set(&ctx->win_updated, 1);
 }
 
-static void fimd_win_disable(struct exynos_drm_crtc *crtc, int zpos)
+static void fimd_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
 {
        struct fimd_context *ctx = crtc->ctx;
-       struct fimd_win_data *win_data;
-       int win = zpos;
-
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
+       struct exynos_drm_plane *plane;
 
        if (win < 0 || win >= WINDOWS_NR)
                return;
 
-       win_data = &ctx->win_data[win];
+       plane = &ctx->planes[win];
 
        if (ctx->suspended) {
                /* do not resume this window*/
-               win_data->resume = false;
+               plane->resume = false;
                return;
        }
 
@@ -814,42 +761,42 @@ static void fimd_win_disable(struct exynos_drm_crtc *crtc, int zpos)
        /* unprotect windows */
        fimd_shadow_protect_win(ctx, win, false);
 
-       win_data->enabled = false;
+       plane->enabled = false;
 }
 
 static void fimd_window_suspend(struct fimd_context *ctx)
 {
-       struct fimd_win_data *win_data;
+       struct exynos_drm_plane *plane;
        int i;
 
        for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               win_data->resume = win_data->enabled;
-               if (win_data->enabled)
+               plane = &ctx->planes[i];
+               plane->resume = plane->enabled;
+               if (plane->enabled)
                        fimd_win_disable(ctx->crtc, i);
        }
 }
 
 static void fimd_window_resume(struct fimd_context *ctx)
 {
-       struct fimd_win_data *win_data;
+       struct exynos_drm_plane *plane;
        int i;
 
        for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               win_data->enabled = win_data->resume;
-               win_data->resume = false;
+               plane = &ctx->planes[i];
+               plane->enabled = plane->resume;
+               plane->resume = false;
        }
 }
 
 static void fimd_apply(struct fimd_context *ctx)
 {
-       struct fimd_win_data *win_data;
+       struct exynos_drm_plane *plane;
        int i;
 
        for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               if (win_data->enabled)
+               plane = &ctx->planes[i];
+               if (plane->enabled)
                        fimd_win_commit(ctx->crtc, i);
                else
                        fimd_win_disable(ctx->crtc, i);
@@ -1006,7 +953,6 @@ static struct exynos_drm_crtc_ops fimd_crtc_ops = {
        .enable_vblank = fimd_enable_vblank,
        .disable_vblank = fimd_disable_vblank,
        .wait_for_vblank = fimd_wait_for_vblank,
-       .win_mode_set = fimd_win_mode_set,
        .win_commit = fimd_win_commit,
        .win_disable = fimd_win_disable,
        .te_handler = fimd_te_handler,
@@ -1052,14 +998,29 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
        struct fimd_context *ctx = dev_get_drvdata(dev);
        struct drm_device *drm_dev = data;
        struct exynos_drm_private *priv = drm_dev->dev_private;
+       struct exynos_drm_plane *exynos_plane;
+       enum drm_plane_type type;
+       unsigned int zpos;
        int ret;
 
        ctx->drm_dev = drm_dev;
        ctx->pipe = priv->pipe++;
 
-       ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
-                                          EXYNOS_DISPLAY_TYPE_LCD,
+       for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
+               type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
+                                               DRM_PLANE_TYPE_OVERLAY;
+               ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
+                                       1 << ctx->pipe, type, zpos);
+               if (ret)
+                       return ret;
+       }
+
+       exynos_plane = &ctx->planes[ctx->default_win];
+       ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
+                                          ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD,
                                           &fimd_crtc_ops, ctx);
+       if (IS_ERR(ctx->crtc))
+               return PTR_ERR(ctx->crtc);
 
        if (ctx->display)
                exynos_drm_create_enc_conn(drm_dev, ctx->display);
@@ -1231,6 +1192,24 @@ static int fimd_remove(struct platform_device *pdev)
        return 0;
 }
 
+void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable)
+{
+       struct fimd_context *ctx = crtc->ctx;
+       u32 val;
+
+       /*
+        * Only Exynos 5250, 5260, 5410 and 542x requires enabling DP/MIE
+        * clock. On these SoCs the bootloader may enable it but any
+        * power domain off/on will reset it to disable state.
+        */
+       if (ctx->driver_data != &exynos5_fimd_driver_data)
+               return;
+
+       val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE;
+       writel(DP_MIE_CLK_DP_ENABLE, ctx->regs + DP_MIE_CLKCON);
+}
+EXPORT_SYMBOL_GPL(fimd_dp_clock_enable);
+
 struct platform_driver fimd_driver = {
        .probe          = fimd_probe,
        .remove         = fimd_remove,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.h b/drivers/gpu/drm/exynos/exynos_drm_fimd.h
new file mode 100644 (file)
index 0000000..b4fcaa5
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef _EXYNOS_DRM_FIMD_H_
+#define _EXYNOS_DRM_FIMD_H_
+
+extern void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable);
+
+#endif /* _EXYNOS_DRM_FIMD_H_ */
index d5ad17dfc24ddc1eafbce0c212a607c5598cbc1c..b7f1cbc46cc2c306a5135e52cd19959462d3667e 100644 (file)
@@ -476,6 +476,45 @@ err_clear:
        return ret;
 }
 
+static int ipp_validate_mem_node(struct drm_device *drm_dev,
+                                struct drm_exynos_ipp_mem_node *m_node,
+                                struct drm_exynos_ipp_cmd_node *c_node)
+{
+       struct drm_exynos_ipp_config *ipp_cfg;
+       unsigned int num_plane;
+       unsigned long min_size, size;
+       unsigned int bpp;
+       int i;
+
+       /* The property id should already be varified */
+       ipp_cfg = &c_node->property.config[m_node->prop_id];
+       num_plane = drm_format_num_planes(ipp_cfg->fmt);
+
+       /**
+        * This is a rather simplified validation of a memory node.
+        * It basically verifies provided gem object handles
+        * and the buffer sizes with respect to current configuration.
+        * This is not the best that can be done
+        * but it seems more than enough
+        */
+       for (i = 0; i < num_plane; ++i) {
+               if (!m_node->buf_info.handles[i]) {
+                       DRM_ERROR("invalid handle for plane %d\n", i);
+                       return -EINVAL;
+               }
+               bpp = drm_format_plane_cpp(ipp_cfg->fmt, i);
+               min_size = (ipp_cfg->sz.hsize * ipp_cfg->sz.vsize * bpp) >> 3;
+               size = exynos_drm_gem_get_size(drm_dev,
+                                              m_node->buf_info.handles[i],
+                                              c_node->filp);
+               if (min_size > size) {
+                       DRM_ERROR("invalid size for plane %d\n", i);
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
 static int ipp_put_mem_node(struct drm_device *drm_dev,
                struct drm_exynos_ipp_cmd_node *c_node,
                struct drm_exynos_ipp_mem_node *m_node)
@@ -552,6 +591,11 @@ static struct drm_exynos_ipp_mem_node
        }
 
        mutex_lock(&c_node->mem_lock);
+       if (ipp_validate_mem_node(drm_dev, m_node, c_node)) {
+               ipp_put_mem_node(drm_dev, c_node, m_node);
+               mutex_unlock(&c_node->mem_lock);
+               return ERR_PTR(-EFAULT);
+       }
        list_add_tail(&m_node->list, &c_node->mem_list[qbuf->ops_id]);
        mutex_unlock(&c_node->mem_lock);
 
index 8ad5b7294eb4801c189fa3b2cdf90ebb24606fd3..13ea3349363b153a8225aece3acc3e70a05dbe51 100644 (file)
@@ -92,7 +92,6 @@ void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
                          uint32_t src_w, uint32_t src_h)
 {
        struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
-       struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
        unsigned int actual_w;
        unsigned int actual_h;
 
@@ -111,13 +110,17 @@ void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
                crtc_y = 0;
        }
 
+       /* set ratio */
+       exynos_plane->h_ratio = (src_w << 16) / crtc_w;
+       exynos_plane->v_ratio = (src_h << 16) / crtc_h;
+
        /* set drm framebuffer data. */
-       exynos_plane->fb_x = src_x;
-       exynos_plane->fb_y = src_y;
+       exynos_plane->src_x = src_x;
+       exynos_plane->src_y = src_y;
+       exynos_plane->src_width = (actual_w * exynos_plane->h_ratio) >> 16;
+       exynos_plane->src_height = (actual_h * exynos_plane->v_ratio) >> 16;
        exynos_plane->fb_width = fb->width;
        exynos_plane->fb_height = fb->height;
-       exynos_plane->src_width = src_w;
-       exynos_plane->src_height = src_h;
        exynos_plane->bpp = fb->bits_per_pixel;
        exynos_plane->pitch = fb->pitches[0];
        exynos_plane->pixel_format = fb->pixel_format;
@@ -139,9 +142,6 @@ void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
                        exynos_plane->crtc_width, exynos_plane->crtc_height);
 
        plane->crtc = crtc;
-
-       if (exynos_crtc->ops->win_mode_set)
-               exynos_crtc->ops->win_mode_set(exynos_crtc, exynos_plane);
 }
 
 int
@@ -182,39 +182,14 @@ static int exynos_disable_plane(struct drm_plane *plane)
        return 0;
 }
 
-static void exynos_plane_destroy(struct drm_plane *plane)
-{
-       struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
-
-       exynos_disable_plane(plane);
-       drm_plane_cleanup(plane);
-       kfree(exynos_plane);
-}
-
-static int exynos_plane_set_property(struct drm_plane *plane,
-                                    struct drm_property *property,
-                                    uint64_t val)
-{
-       struct drm_device *dev = plane->dev;
-       struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
-       struct exynos_drm_private *dev_priv = dev->dev_private;
-
-       if (property == dev_priv->plane_zpos_property) {
-               exynos_plane->zpos = val;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
 static struct drm_plane_funcs exynos_plane_funcs = {
        .update_plane   = exynos_update_plane,
        .disable_plane  = exynos_disable_plane,
-       .destroy        = exynos_plane_destroy,
-       .set_property   = exynos_plane_set_property,
+       .destroy        = drm_plane_cleanup,
 };
 
-static void exynos_plane_attach_zpos_property(struct drm_plane *plane)
+static void exynos_plane_attach_zpos_property(struct drm_plane *plane,
+                                             unsigned int zpos)
 {
        struct drm_device *dev = plane->dev;
        struct exynos_drm_private *dev_priv = dev->dev_private;
@@ -222,41 +197,36 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane)
 
        prop = dev_priv->plane_zpos_property;
        if (!prop) {
-               prop = drm_property_create_range(dev, 0, "zpos", 0,
-                                                MAX_PLANE - 1);
+               prop = drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE,
+                                                "zpos", 0, MAX_PLANE - 1);
                if (!prop)
                        return;
 
                dev_priv->plane_zpos_property = prop;
        }
 
-       drm_object_attach_property(&plane->base, prop, 0);
+       drm_object_attach_property(&plane->base, prop, zpos);
 }
 
-struct drm_plane *exynos_plane_init(struct drm_device *dev,
-                                   unsigned long possible_crtcs,
-                                   enum drm_plane_type type)
+int exynos_plane_init(struct drm_device *dev,
+                     struct exynos_drm_plane *exynos_plane,
+                     unsigned long possible_crtcs, enum drm_plane_type type,
+                     unsigned int zpos)
 {
-       struct exynos_drm_plane *exynos_plane;
        int err;
 
-       exynos_plane = kzalloc(sizeof(struct exynos_drm_plane), GFP_KERNEL);
-       if (!exynos_plane)
-               return ERR_PTR(-ENOMEM);
-
        err = drm_universal_plane_init(dev, &exynos_plane->base, possible_crtcs,
                                       &exynos_plane_funcs, formats,
                                       ARRAY_SIZE(formats), type);
        if (err) {
                DRM_ERROR("failed to initialize plane\n");
-               kfree(exynos_plane);
-               return ERR_PTR(err);
+               return err;
        }
 
-       if (type == DRM_PLANE_TYPE_PRIMARY)
-               exynos_plane->zpos = DEFAULT_ZPOS;
-       else
-               exynos_plane_attach_zpos_property(&exynos_plane->base);
+       exynos_plane->zpos = zpos;
 
-       return &exynos_plane->base;
+       if (type == DRM_PLANE_TYPE_OVERLAY)
+               exynos_plane_attach_zpos_property(&exynos_plane->base, zpos);
+
+       return 0;
 }
index 9d3c374e7b3ec44ea3fe36c078e2819543bf3c6a..f360590d14128f2f48329a0da2cfb177a89d62bd 100644 (file)
@@ -20,6 +20,7 @@ int exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                        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 drm_plane *exynos_plane_init(struct drm_device *dev,
-                                   unsigned long possible_crtcs,
-                                   enum drm_plane_type type);
+int exynos_plane_init(struct drm_device *dev,
+                     struct exynos_drm_plane *exynos_plane,
+                     unsigned long possible_crtcs, enum drm_plane_type type,
+                     unsigned int zpos);
index b886972b5888e4360fa441a617c8f8c9026d19d6..27e84ec21694d587f26a78d258c216d52bd450ea 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_crtc.h"
+#include "exynos_drm_plane.h"
 #include "exynos_drm_encoder.h"
 #include "exynos_drm_vidi.h"
 
 #define ctx_from_connector(c)  container_of(c, struct vidi_context, \
                                        connector)
 
-struct vidi_win_data {
-       unsigned int            offset_x;
-       unsigned int            offset_y;
-       unsigned int            ovl_width;
-       unsigned int            ovl_height;
-       unsigned int            fb_width;
-       unsigned int            fb_height;
-       unsigned int            bpp;
-       dma_addr_t              dma_addr;
-       unsigned int            buf_offsize;
-       unsigned int            line_size;      /* bytes */
-       bool                    enabled;
-};
-
 struct vidi_context {
        struct exynos_drm_display       display;
        struct platform_device          *pdev;
@@ -53,7 +40,7 @@ struct vidi_context {
        struct exynos_drm_crtc          *crtc;
        struct drm_encoder              *encoder;
        struct drm_connector            connector;
-       struct vidi_win_data            win_data[WINDOWS_NR];
+       struct exynos_drm_plane         planes[WINDOWS_NR];
        struct edid                     *raw_edid;
        unsigned int                    clkdiv;
        unsigned int                    default_win;
@@ -97,19 +84,6 @@ static const char fake_edid_info[] = {
        0x00, 0x00, 0x00, 0x06
 };
 
-static void vidi_apply(struct vidi_context *ctx)
-{
-       struct exynos_drm_crtc_ops *crtc_ops = ctx->crtc->ops;
-       struct vidi_win_data *win_data;
-       int i;
-
-       for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               if (win_data->enabled && (crtc_ops && crtc_ops->win_commit))
-                       crtc_ops->win_commit(ctx->crtc, i);
-       }
-}
-
 static int vidi_enable_vblank(struct exynos_drm_crtc *crtc)
 {
        struct vidi_context *ctx = crtc->ctx;
@@ -143,104 +117,46 @@ static void vidi_disable_vblank(struct exynos_drm_crtc *crtc)
                ctx->vblank_on = false;
 }
 
-static void vidi_win_mode_set(struct exynos_drm_crtc *crtc,
-                       struct exynos_drm_plane *plane)
-{
-       struct vidi_context *ctx = crtc->ctx;
-       struct vidi_win_data *win_data;
-       int win;
-       unsigned long offset;
-
-       if (!plane) {
-               DRM_ERROR("plane is NULL\n");
-               return;
-       }
-
-       win = plane->zpos;
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
-
-       if (win < 0 || win >= WINDOWS_NR)
-               return;
-
-       offset = plane->fb_x * (plane->bpp >> 3);
-       offset += plane->fb_y * plane->pitch;
-
-       DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, plane->pitch);
-
-       win_data = &ctx->win_data[win];
-
-       win_data->offset_x = plane->crtc_x;
-       win_data->offset_y = plane->crtc_y;
-       win_data->ovl_width = plane->crtc_width;
-       win_data->ovl_height = plane->crtc_height;
-       win_data->fb_width = plane->fb_width;
-       win_data->fb_height = plane->fb_height;
-       win_data->dma_addr = plane->dma_addr[0] + offset;
-       win_data->bpp = plane->bpp;
-       win_data->buf_offsize = (plane->fb_width - plane->crtc_width) *
-                               (plane->bpp >> 3);
-       win_data->line_size = plane->crtc_width * (plane->bpp >> 3);
-
-       /*
-        * some parts of win_data should be transferred to user side
-        * through specific ioctl.
-        */
-
-       DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
-                       win_data->offset_x, win_data->offset_y);
-       DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
-                       win_data->ovl_width, win_data->ovl_height);
-       DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
-       DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
-                       plane->fb_width, plane->crtc_width);
-}
-
-static void vidi_win_commit(struct exynos_drm_crtc *crtc, int zpos)
+static void vidi_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
 {
        struct vidi_context *ctx = crtc->ctx;
-       struct vidi_win_data *win_data;
-       int win = zpos;
+       struct exynos_drm_plane *plane;
 
        if (ctx->suspended)
                return;
 
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
-
        if (win < 0 || win >= WINDOWS_NR)
                return;
 
-       win_data = &ctx->win_data[win];
+       plane = &ctx->planes[win];
 
-       win_data->enabled = true;
+       plane->enabled = true;
 
-       DRM_DEBUG_KMS("dma_addr = %pad\n", &win_data->dma_addr);
+       DRM_DEBUG_KMS("dma_addr = %pad\n", plane->dma_addr);
 
        if (ctx->vblank_on)
                schedule_work(&ctx->work);
 }
 
-static void vidi_win_disable(struct exynos_drm_crtc *crtc, int zpos)
+static void vidi_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
 {
        struct vidi_context *ctx = crtc->ctx;
-       struct vidi_win_data *win_data;
-       int win = zpos;
-
-       if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
+       struct exynos_drm_plane *plane;
 
        if (win < 0 || win >= WINDOWS_NR)
                return;
 
-       win_data = &ctx->win_data[win];
-       win_data->enabled = false;
+       plane = &ctx->planes[win];
+       plane->enabled = false;
 
        /* TODO. */
 }
 
 static int vidi_power_on(struct vidi_context *ctx, bool enable)
 {
+       struct exynos_drm_plane *plane;
+       int i;
+
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        if (enable != false && enable != true)
@@ -253,7 +169,11 @@ static int vidi_power_on(struct vidi_context *ctx, bool enable)
                if (test_and_clear_bit(0, &ctx->irq_flags))
                        vidi_enable_vblank(ctx->crtc);
 
-               vidi_apply(ctx);
+               for (i = 0; i < WINDOWS_NR; i++) {
+                       plane = &ctx->planes[i];
+                       if (plane->enabled)
+                               vidi_win_commit(ctx->crtc, i);
+               }
        } else {
                ctx->suspended = true;
        }
@@ -301,7 +221,6 @@ static struct exynos_drm_crtc_ops vidi_crtc_ops = {
        .dpms = vidi_dpms,
        .enable_vblank = vidi_enable_vblank,
        .disable_vblank = vidi_disable_vblank,
-       .win_mode_set = vidi_win_mode_set,
        .win_commit = vidi_win_commit,
        .win_disable = vidi_win_disable,
 };
@@ -543,12 +462,25 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
 {
        struct vidi_context *ctx = dev_get_drvdata(dev);
        struct drm_device *drm_dev = data;
+       struct exynos_drm_plane *exynos_plane;
+       enum drm_plane_type type;
+       unsigned int zpos;
        int ret;
 
        vidi_ctx_initialize(ctx, drm_dev);
 
-       ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
-                                          EXYNOS_DISPLAY_TYPE_VIDI,
+       for (zpos = 0; zpos < WINDOWS_NR; zpos++) {
+               type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
+                                               DRM_PLANE_TYPE_OVERLAY;
+               ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
+                                       1 << ctx->pipe, type, zpos);
+               if (ret)
+                       return ret;
+       }
+
+       exynos_plane = &ctx->planes[ctx->default_win];
+       ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
+                                          ctx->pipe, EXYNOS_DISPLAY_TYPE_VIDI,
                                           &vidi_crtc_ops, ctx);
        if (IS_ERR(ctx->crtc)) {
                DRM_ERROR("failed to create crtc.\n");
index 229b3613c60b4217dc773f90b0a0bd379480b7a8..5eba971f394a454b9cab53ff023bb4a74e63d826 100644 (file)
@@ -2007,7 +2007,7 @@ static void hdmi_mode_set(struct exynos_drm_display *display,
        DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
                m->hdisplay, m->vdisplay,
                m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
-               "INTERLACED" : "PROGERESSIVE");
+               "INTERLACED" : "PROGRESSIVE");
 
        /* preserve mode information for later use. */
        drm_mode_copy(&hdata->current_mode, mode);
@@ -2101,7 +2101,7 @@ static void hdmi_dpms(struct exynos_drm_display *display, int mode)
        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;
+       const struct drm_crtc_helper_funcs *funcs = NULL;
 
        DRM_DEBUG_KMS("mode %d\n", mode);
 
index 3518bc4654c5c9381acdb8d7253395e0466c8adc..fbec750574e64a3158b232d15ef309b29ed5340c 100644 (file)
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_crtc.h"
+#include "exynos_drm_plane.h"
 #include "exynos_drm_iommu.h"
 #include "exynos_mixer.h"
 
 #define MIXER_WIN_NR           3
 #define MIXER_DEFAULT_WIN      0
 
-struct hdmi_win_data {
-       dma_addr_t              dma_addr;
-       dma_addr_t              chroma_dma_addr;
-       uint32_t                pixel_format;
-       unsigned int            bpp;
-       unsigned int            crtc_x;
-       unsigned int            crtc_y;
-       unsigned int            crtc_width;
-       unsigned int            crtc_height;
-       unsigned int            fb_x;
-       unsigned int            fb_y;
-       unsigned int            fb_width;
-       unsigned int            fb_height;
-       unsigned int            src_width;
-       unsigned int            src_height;
-       unsigned int            mode_width;
-       unsigned int            mode_height;
-       unsigned int            scan_flags;
-       bool                    enabled;
-       bool                    resume;
-};
-
 struct mixer_resources {
        int                     irq;
        void __iomem            *mixer_regs;
@@ -89,6 +68,7 @@ struct mixer_context {
        struct device           *dev;
        struct drm_device       *drm_dev;
        struct exynos_drm_crtc  *crtc;
+       struct exynos_drm_plane planes[MIXER_WIN_NR];
        int                     pipe;
        bool                    interlace;
        bool                    powered;
@@ -98,7 +78,6 @@ struct mixer_context {
 
        struct mutex            mixer_mutex;
        struct mixer_resources  mixer_res;
-       struct hdmi_win_data    win_data[MIXER_WIN_NR];
        enum mixer_version_id   mxr_ver;
        wait_queue_head_t       wait_vsync_queue;
        atomic_t                wait_vsync_event;
@@ -288,7 +267,7 @@ static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
 
        /* choosing between interlace and progressive mode */
        val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
-                               MXR_CFG_SCAN_PROGRASSIVE);
+                               MXR_CFG_SCAN_PROGRESSIVE);
 
        if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
                /* choosing between proper HD and SD mode */
@@ -402,17 +381,16 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
 {
        struct mixer_resources *res = &ctx->mixer_res;
        unsigned long flags;
-       struct hdmi_win_data *win_data;
-       unsigned int x_ratio, y_ratio;
+       struct exynos_drm_plane *plane;
        unsigned int buf_num = 1;
        dma_addr_t luma_addr[2], chroma_addr[2];
        bool tiled_mode = false;
        bool crcb_mode = false;
        u32 val;
 
-       win_data = &ctx->win_data[win];
+       plane = &ctx->planes[win];
 
-       switch (win_data->pixel_format) {
+       switch (plane->pixel_format) {
        case DRM_FORMAT_NV12:
                crcb_mode = false;
                buf_num = 2;
@@ -420,35 +398,31 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
        /* TODO: single buffer format NV12, NV21 */
        default:
                /* ignore pixel format at disable time */
-               if (!win_data->dma_addr)
+               if (!plane->dma_addr[0])
                        break;
 
                DRM_ERROR("pixel format for vp is wrong [%d].\n",
-                               win_data->pixel_format);
+                               plane->pixel_format);
                return;
        }
 
-       /* scaling feature: (src << 16) / dst */
-       x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
-       y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
-
        if (buf_num == 2) {
-               luma_addr[0] = win_data->dma_addr;
-               chroma_addr[0] = win_data->chroma_dma_addr;
+               luma_addr[0] = plane->dma_addr[0];
+               chroma_addr[0] = plane->dma_addr[1];
        } else {
-               luma_addr[0] = win_data->dma_addr;
-               chroma_addr[0] = win_data->dma_addr
-                       + (win_data->fb_width * win_data->fb_height);
+               luma_addr[0] = plane->dma_addr[0];
+               chroma_addr[0] = plane->dma_addr[0]
+                       + (plane->pitch * plane->fb_height);
        }
 
-       if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
+       if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) {
                ctx->interlace = true;
                if (tiled_mode) {
                        luma_addr[1] = luma_addr[0] + 0x40;
                        chroma_addr[1] = chroma_addr[0] + 0x40;
                } else {
-                       luma_addr[1] = luma_addr[0] + win_data->fb_width;
-                       chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
+                       luma_addr[1] = luma_addr[0] + plane->pitch;
+                       chroma_addr[1] = chroma_addr[0] + plane->pitch;
                }
        } else {
                ctx->interlace = false;
@@ -469,30 +443,30 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
        vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
 
        /* setting size of input image */
-       vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
-               VP_IMG_VSIZE(win_data->fb_height));
+       vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(plane->pitch) |
+               VP_IMG_VSIZE(plane->fb_height));
        /* chroma height has to reduced by 2 to avoid chroma distorions */
-       vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) |
-               VP_IMG_VSIZE(win_data->fb_height / 2));
+       vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(plane->pitch) |
+               VP_IMG_VSIZE(plane->fb_height / 2));
 
-       vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
-       vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
+       vp_reg_write(res, VP_SRC_WIDTH, plane->src_width);
+       vp_reg_write(res, VP_SRC_HEIGHT, plane->src_height);
        vp_reg_write(res, VP_SRC_H_POSITION,
-                       VP_SRC_H_POSITION_VAL(win_data->fb_x));
-       vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
+                       VP_SRC_H_POSITION_VAL(plane->src_x));
+       vp_reg_write(res, VP_SRC_V_POSITION, plane->src_y);
 
-       vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
-       vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
+       vp_reg_write(res, VP_DST_WIDTH, plane->crtc_width);
+       vp_reg_write(res, VP_DST_H_POSITION, plane->crtc_x);
        if (ctx->interlace) {
-               vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
-               vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
+               vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height / 2);
+               vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y / 2);
        } else {
-               vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
-               vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
+               vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height);
+               vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y);
        }
 
-       vp_reg_write(res, VP_H_RATIO, x_ratio);
-       vp_reg_write(res, VP_V_RATIO, y_ratio);
+       vp_reg_write(res, VP_H_RATIO, plane->h_ratio);
+       vp_reg_write(res, VP_V_RATIO, plane->v_ratio);
 
        vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
 
@@ -502,8 +476,8 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
        vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
        vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
 
-       mixer_cfg_scan(ctx, win_data->mode_height);
-       mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
+       mixer_cfg_scan(ctx, plane->mode_height);
+       mixer_cfg_rgb_fmt(ctx, plane->mode_height);
        mixer_cfg_layer(ctx, win, true);
        mixer_run(ctx);
 
@@ -520,25 +494,49 @@ static void mixer_layer_update(struct mixer_context *ctx)
        mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
 }
 
+static int mixer_setup_scale(const struct exynos_drm_plane *plane,
+               unsigned int *x_ratio, unsigned int *y_ratio)
+{
+       if (plane->crtc_width != plane->src_width) {
+               if (plane->crtc_width == 2 * plane->src_width)
+                       *x_ratio = 1;
+               else
+                       goto fail;
+       }
+
+       if (plane->crtc_height != plane->src_height) {
+               if (plane->crtc_height == 2 * plane->src_height)
+                       *y_ratio = 1;
+               else
+                       goto fail;
+       }
+
+       return 0;
+
+fail:
+       DRM_DEBUG_KMS("only 2x width/height scaling of plane supported\n");
+       return -ENOTSUPP;
+}
+
 static void mixer_graph_buffer(struct mixer_context *ctx, int win)
 {
        struct mixer_resources *res = &ctx->mixer_res;
        unsigned long flags;
-       struct hdmi_win_data *win_data;
-       unsigned int x_ratio, y_ratio;
+       struct exynos_drm_plane *plane;
+       unsigned int x_ratio = 0, y_ratio = 0;
        unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
        dma_addr_t dma_addr;
        unsigned int fmt;
        u32 val;
 
-       win_data = &ctx->win_data[win];
+       plane = &ctx->planes[win];
 
        #define RGB565 4
        #define ARGB1555 5
        #define ARGB4444 6
        #define ARGB8888 7
 
-       switch (win_data->bpp) {
+       switch (plane->bpp) {
        case 16:
                fmt = ARGB4444;
                break;
@@ -549,21 +547,21 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
                fmt = ARGB8888;
        }
 
-       /* 2x scaling feature */
-       x_ratio = 0;
-       y_ratio = 0;
+       /* check if mixer supports requested scaling setup */
+       if (mixer_setup_scale(plane, &x_ratio, &y_ratio))
+               return;
 
-       dst_x_offset = win_data->crtc_x;
-       dst_y_offset = win_data->crtc_y;
+       dst_x_offset = plane->crtc_x;
+       dst_y_offset = plane->crtc_y;
 
        /* converting dma address base and source offset */
-       dma_addr = win_data->dma_addr
-               + (win_data->fb_x * win_data->bpp >> 3)
-               + (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3);
+       dma_addr = plane->dma_addr[0]
+               + (plane->src_x * plane->bpp >> 3)
+               + (plane->src_y * plane->pitch);
        src_x_offset = 0;
        src_y_offset = 0;
 
-       if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
+       if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE)
                ctx->interlace = true;
        else
                ctx->interlace = false;
@@ -576,18 +574,19 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
                MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
 
        /* setup geometry */
-       mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
+       mixer_reg_write(res, MXR_GRAPHIC_SPAN(win),
+                       plane->pitch / (plane->bpp >> 3));
 
        /* setup display size */
        if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
                win == MIXER_DEFAULT_WIN) {
-               val  = MXR_MXR_RES_HEIGHT(win_data->mode_height);
-               val |= MXR_MXR_RES_WIDTH(win_data->mode_width);
+               val  = MXR_MXR_RES_HEIGHT(plane->mode_height);
+               val |= MXR_MXR_RES_WIDTH(plane->mode_width);
                mixer_reg_write(res, MXR_RESOLUTION, val);
        }
 
-       val  = MXR_GRP_WH_WIDTH(win_data->crtc_width);
-       val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
+       val  = MXR_GRP_WH_WIDTH(plane->src_width);
+       val |= MXR_GRP_WH_HEIGHT(plane->src_height);
        val |= MXR_GRP_WH_H_SCALE(x_ratio);
        val |= MXR_GRP_WH_V_SCALE(y_ratio);
        mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
@@ -605,8 +604,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
        /* set buffer address to mixer */
        mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
 
-       mixer_cfg_scan(ctx, win_data->mode_height);
-       mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
+       mixer_cfg_scan(ctx, plane->mode_height);
+       mixer_cfg_rgb_fmt(ctx, plane->mode_height);
        mixer_cfg_layer(ctx, win, true);
 
        /* layer update mandatory for mixer 16.0.33.0 */
@@ -918,62 +917,9 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
        mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
 }
 
-static void mixer_win_mode_set(struct exynos_drm_crtc *crtc,
-                       struct exynos_drm_plane *plane)
-{
-       struct mixer_context *mixer_ctx = crtc->ctx;
-       struct hdmi_win_data *win_data;
-       int win;
-
-       if (!plane) {
-               DRM_ERROR("plane is NULL\n");
-               return;
-       }
-
-       DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
-                                plane->fb_width, plane->fb_height,
-                                plane->fb_x, plane->fb_y,
-                                plane->crtc_width, plane->crtc_height,
-                                plane->crtc_x, plane->crtc_y);
-
-       win = plane->zpos;
-       if (win == DEFAULT_ZPOS)
-               win = MIXER_DEFAULT_WIN;
-
-       if (win < 0 || win >= MIXER_WIN_NR) {
-               DRM_ERROR("mixer window[%d] is wrong\n", win);
-               return;
-       }
-
-       win_data = &mixer_ctx->win_data[win];
-
-       win_data->dma_addr = plane->dma_addr[0];
-       win_data->chroma_dma_addr = plane->dma_addr[1];
-       win_data->pixel_format = plane->pixel_format;
-       win_data->bpp = plane->bpp;
-
-       win_data->crtc_x = plane->crtc_x;
-       win_data->crtc_y = plane->crtc_y;
-       win_data->crtc_width = plane->crtc_width;
-       win_data->crtc_height = plane->crtc_height;
-
-       win_data->fb_x = plane->fb_x;
-       win_data->fb_y = plane->fb_y;
-       win_data->fb_width = plane->fb_width;
-       win_data->fb_height = plane->fb_height;
-       win_data->src_width = plane->src_width;
-       win_data->src_height = plane->src_height;
-
-       win_data->mode_width = plane->mode_width;
-       win_data->mode_height = plane->mode_height;
-
-       win_data->scan_flags = plane->scan_flag;
-}
-
-static void mixer_win_commit(struct exynos_drm_crtc *crtc, int zpos)
+static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win)
 {
        struct mixer_context *mixer_ctx = crtc->ctx;
-       int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
 
        DRM_DEBUG_KMS("win: %d\n", win);
 
@@ -989,14 +935,13 @@ static void mixer_win_commit(struct exynos_drm_crtc *crtc, int zpos)
        else
                mixer_graph_buffer(mixer_ctx, win);
 
-       mixer_ctx->win_data[win].enabled = true;
+       mixer_ctx->planes[win].enabled = true;
 }
 
-static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos)
+static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win)
 {
        struct mixer_context *mixer_ctx = crtc->ctx;
        struct mixer_resources *res = &mixer_ctx->mixer_res;
-       int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
        unsigned long flags;
 
        DRM_DEBUG_KMS("win: %d\n", win);
@@ -1004,7 +949,7 @@ static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos)
        mutex_lock(&mixer_ctx->mixer_mutex);
        if (!mixer_ctx->powered) {
                mutex_unlock(&mixer_ctx->mixer_mutex);
-               mixer_ctx->win_data[win].resume = false;
+               mixer_ctx->planes[win].resume = false;
                return;
        }
        mutex_unlock(&mixer_ctx->mixer_mutex);
@@ -1017,7 +962,7 @@ static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos)
        mixer_vsync_set_update(mixer_ctx, true);
        spin_unlock_irqrestore(&res->reg_slock, flags);
 
-       mixer_ctx->win_data[win].enabled = false;
+       mixer_ctx->planes[win].enabled = false;
 }
 
 static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
@@ -1054,12 +999,12 @@ static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
 
 static void mixer_window_suspend(struct mixer_context *ctx)
 {
-       struct hdmi_win_data *win_data;
+       struct exynos_drm_plane *plane;
        int i;
 
        for (i = 0; i < MIXER_WIN_NR; i++) {
-               win_data = &ctx->win_data[i];
-               win_data->resume = win_data->enabled;
+               plane = &ctx->planes[i];
+               plane->resume = plane->enabled;
                mixer_win_disable(ctx->crtc, i);
        }
        mixer_wait_for_vblank(ctx->crtc);
@@ -1067,14 +1012,14 @@ static void mixer_window_suspend(struct mixer_context *ctx)
 
 static void mixer_window_resume(struct mixer_context *ctx)
 {
-       struct hdmi_win_data *win_data;
+       struct exynos_drm_plane *plane;
        int i;
 
        for (i = 0; i < MIXER_WIN_NR; i++) {
-               win_data = &ctx->win_data[i];
-               win_data->enabled = win_data->resume;
-               win_data->resume = false;
-               if (win_data->enabled)
+               plane = &ctx->planes[i];
+               plane->enabled = plane->resume;
+               plane->resume = false;
+               if (plane->enabled)
                        mixer_win_commit(ctx->crtc, i);
        }
 }
@@ -1186,7 +1131,6 @@ static struct exynos_drm_crtc_ops mixer_crtc_ops = {
        .enable_vblank          = mixer_enable_vblank,
        .disable_vblank         = mixer_disable_vblank,
        .wait_for_vblank        = mixer_wait_for_vblank,
-       .win_mode_set           = mixer_win_mode_set,
        .win_commit             = mixer_win_commit,
        .win_disable            = mixer_win_disable,
 };
@@ -1250,15 +1194,28 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
 {
        struct mixer_context *ctx = dev_get_drvdata(dev);
        struct drm_device *drm_dev = data;
+       struct exynos_drm_plane *exynos_plane;
+       enum drm_plane_type type;
+       unsigned int zpos;
        int ret;
 
        ret = mixer_initialize(ctx, drm_dev);
        if (ret)
                return ret;
 
-       ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
-                                    EXYNOS_DISPLAY_TYPE_HDMI,
-                                    &mixer_crtc_ops, ctx);
+       for (zpos = 0; zpos < MIXER_WIN_NR; zpos++) {
+               type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY :
+                                               DRM_PLANE_TYPE_OVERLAY;
+               ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
+                                       1 << ctx->pipe, type, zpos);
+               if (ret)
+                       return ret;
+       }
+
+       exynos_plane = &ctx->planes[MIXER_DEFAULT_WIN];
+       ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
+                                          ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI,
+                                          &mixer_crtc_ops, ctx);
        if (IS_ERR(ctx->crtc)) {
                mixer_ctx_remove(ctx);
                ret = PTR_ERR(ctx->crtc);
index 5f32e1a29411842b79ae401916fe9a4114bd1a91..ac60260c2389935c3446b51815f5a6534b9dd1a1 100644 (file)
 #define MXR_CFG_GRP0_ENABLE            (1 << 4)
 #define MXR_CFG_VP_ENABLE              (1 << 3)
 #define MXR_CFG_SCAN_INTERLACE         (0 << 2)
-#define MXR_CFG_SCAN_PROGRASSIVE       (1 << 2)
+#define MXR_CFG_SCAN_PROGRESSIVE       (1 << 2)
 #define MXR_CFG_SCAN_NTSC              (0 << 1)
 #define MXR_CFG_SCAN_PAL               (1 << 1)
 #define MXR_CFG_SCAN_SD                        (0 << 0)
index 66727328832d7563f6e1dc42bc67ea6b48809ee2..7d47b3d5cc0d0be41258c71f4e81b3840be88a2d 100644 (file)
@@ -823,7 +823,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
 
        /* Flush the plane changes */
        {
-               struct drm_crtc_helper_funcs *crtc_funcs =
+               const struct drm_crtc_helper_funcs *crtc_funcs =
                    crtc->helper_private;
                crtc_funcs->mode_set_base(crtc, x, y, old_fb);
        }
index 4268bf2100344167243ff9f7bbb20c0370658eb6..6b1d3340ba1439eb3491a08d3a15cf4dcf38dc2f 100644 (file)
@@ -195,7 +195,7 @@ static int cdv_hdmi_set_property(struct drm_connector *connector,
                                            encoder->crtc->x, encoder->crtc->y, encoder->crtc->primary->fb))
                                        return -1;
                        } else {
-                               struct drm_encoder_helper_funcs *helpers
+                               const struct drm_encoder_helper_funcs *helpers
                                                    = encoder->helper_private;
                                helpers->mode_set(encoder, &crtc->saved_mode,
                                             &crtc->saved_adjusted_mode);
index 0b770396548c6674c88d3b2802695b703189ae7b..211069b2b951733b39b510545ddb04c34ef3d4dc 100644 (file)
@@ -505,7 +505,7 @@ static int cdv_intel_lvds_set_property(struct drm_connector *connector,
                else
                         gma_backlight_set(encoder->dev, value);
        } else if (!strcmp(property->name, "DPMS") && encoder) {
-               struct drm_encoder_helper_funcs *helpers =
+               const struct drm_encoder_helper_funcs *helpers =
                                        encoder->helper_private;
                helpers->dpms(encoder, value);
        }
index 9bb9bddd881a701a4cf387bf31874455d7e9da76..001b450b27b320fd4fd90eba59fbe80544e25d94 100644 (file)
@@ -501,20 +501,20 @@ bool gma_crtc_mode_fixup(struct drm_crtc *crtc,
 
 void gma_crtc_prepare(struct drm_crtc *crtc)
 {
-       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+       const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
        crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
 }
 
 void gma_crtc_commit(struct drm_crtc *crtc)
 {
-       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+       const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
        crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
 }
 
 void gma_crtc_disable(struct drm_crtc *crtc)
 {
        struct gtt_range *gt;
-       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+       const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
 
        crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
 
@@ -656,7 +656,7 @@ void gma_crtc_restore(struct drm_crtc *crtc)
 
 void gma_encoder_prepare(struct drm_encoder *encoder)
 {
-       struct drm_encoder_helper_funcs *encoder_funcs =
+       const struct drm_encoder_helper_funcs *encoder_funcs =
            encoder->helper_private;
        /* lvds has its own version of prepare see psb_intel_lvds_prepare */
        encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
@@ -664,7 +664,7 @@ void gma_encoder_prepare(struct drm_encoder *encoder)
 
 void gma_encoder_commit(struct drm_encoder *encoder)
 {
-       struct drm_encoder_helper_funcs *encoder_funcs =
+       const struct drm_encoder_helper_funcs *encoder_funcs =
            encoder->helper_private;
        /* lvds has its own version of commit see psb_intel_lvds_commit */
        encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
index abf2248da61ecffec15d80fc0d07f0137f7418c0..89f705c3a5eb3a4242a3c2d785bd03f181d82945 100644 (file)
@@ -290,7 +290,7 @@ static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
                                                encoder->crtc->primary->fb))
                                        goto set_prop_error;
                        } else {
-                               struct drm_encoder_helper_funcs *funcs =
+                               const struct drm_encoder_helper_funcs *funcs =
                                                encoder->helper_private;
                                funcs->mode_set(encoder,
                                        &gma_crtc->saved_mode,
index 8cc8a5abbc7bdd0852c1747f3b7924c0650e924d..acd38344b3026806869cf5e7fd06e76f715f13ba 100644 (file)
@@ -849,7 +849,7 @@ static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
 
        /* Flush the plane changes */
        {
-               struct drm_crtc_helper_funcs *crtc_funcs =
+               const struct drm_crtc_helper_funcs *crtc_funcs =
                    crtc->helper_private;
                crtc_funcs->mode_set_base(crtc, x, y, old_fb);
        }
index 2de216c2374f34482f43008e20fab3eaffbb2e2b..1048f0c7c6ce7af84181184fc42133757e59cac7 100644 (file)
@@ -483,7 +483,7 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
 
        /* Flush the plane changes */
        {
-               struct drm_crtc_helper_funcs *crtc_funcs =
+               const struct drm_crtc_helper_funcs *crtc_funcs =
                    crtc->helper_private;
                crtc_funcs->mode_set_base(crtc, x, y, old_fb);
        }
index 54f73f50571ae65f590639df98c389b2ef75d82d..2310d879cdc2d436c5901d5974df8e9de84e1b0f 100644 (file)
@@ -347,7 +347,7 @@ int oaktrail_crtc_hdmi_mode_set(struct drm_crtc *crtc,
 
        /* Flush the plane changes */
        {
-               struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+               const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
                crtc_funcs->mode_set_base(crtc, x, y, old_fb);
        }
 
index b21a09451d1d506836b18f0ab7fb363ebfe7d924..6659da88fe5b3639da95078dc63cb9505b4a69af 100644 (file)
@@ -108,7 +108,7 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
        struct drm_device *dev = crtc->dev;
        struct drm_psb_private *dev_priv = dev->dev_private;
        struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
-       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+       const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
        int pipe = gma_crtc->pipe;
        const struct psb_offset *map = &dev_priv->regmap[pipe];
        int refclk;
index 88aad95bde091ab82e0f5461361cbe682ec8ab10..ce0645d0c1e5f578a39038c73a78102d44dd04c7 100644 (file)
@@ -625,7 +625,7 @@ int psb_intel_lvds_set_property(struct drm_connector *connector,
                else
                         gma_backlight_set(encoder->dev, value);
        } else if (!strcmp(property->name, "DPMS")) {
-               struct drm_encoder_helper_funcs *hfuncs
+               const struct drm_encoder_helper_funcs *hfuncs
                                                = encoder->helper_private;
                hfuncs->dpms(encoder, value);
        }
index 61aa824d45d2115efe9dd716efee3e2e2785c6c9..b728523e194f7581b8e9740b7ddb13e6f5606d56 100644 (file)
@@ -27,12 +27,13 @@ struct adv7511 {
        struct regmap *regmap;
        struct regmap *packet_memory_regmap;
        enum drm_connector_status status;
-       int dpms_mode;
+       bool powered;
 
        unsigned int f_tmds;
 
        unsigned int current_edid_segment;
        uint8_t edid_buf[256];
+       bool edid_read;
 
        wait_queue_head_t wq;
        struct drm_encoder *encoder;
@@ -357,6 +358,48 @@ static void adv7511_set_link_config(struct adv7511 *adv7511,
        adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
 }
 
+static void adv7511_power_on(struct adv7511 *adv7511)
+{
+       adv7511->current_edid_segment = -1;
+
+       regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
+                    ADV7511_INT0_EDID_READY);
+       regmap_write(adv7511->regmap, ADV7511_REG_INT(1),
+                    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 enabling 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);
+
+       adv7511->powered = true;
+}
+
+static void adv7511_power_off(struct adv7511 *adv7511)
+{
+       /* 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);
+
+       adv7511->powered = false;
+}
+
 /* -----------------------------------------------------------------------------
  * Interrupt and hotplug detection
  */
@@ -379,69 +422,71 @@ static bool adv7511_hpd(struct adv7511 *adv7511)
        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)
+static int adv7511_irq_process(struct adv7511 *adv7511)
 {
        unsigned int irq0, irq1;
-       unsigned int pending;
        int ret;
 
        ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0);
        if (ret < 0)
-               return 0;
+               return ret;
+
        ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(1), &irq1);
        if (ret < 0)
-               return 0;
+               return ret;
 
-       pending = (irq1 << 8) | irq0;
+       regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0);
+       regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
 
-       return pending & irq;
+       if (irq0 & ADV7511_INT0_HDP)
+               drm_helper_hpd_irq_event(adv7511->encoder->dev);
+
+       if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
+               adv7511->edid_read = true;
+
+               if (adv7511->i2c_main->irq)
+                       wake_up_all(&adv7511->wq);
+       }
+
+       return 0;
 }
 
-static int adv7511_wait_for_interrupt(struct adv7511 *adv7511, int irq,
-                                     int timeout)
+static irqreturn_t adv7511_irq_handler(int irq, void *devid)
+{
+       struct adv7511 *adv7511 = devid;
+       int ret;
+
+       ret = adv7511_irq_process(adv7511);
+       return ret < 0 ? IRQ_NONE : IRQ_HANDLED;
+}
+
+/* -----------------------------------------------------------------------------
+ * EDID retrieval
+ */
+
+static int adv7511_wait_for_edid(struct adv7511 *adv7511, 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);
+                               adv7511->edid_read, msecs_to_jiffies(timeout));
        } else {
-               if (timeout < 25)
-                       timeout = 25;
-               do {
-                       pending = adv7511_is_interrupt_pending(adv7511, irq);
-                       if (pending)
+               for (; timeout > 0; timeout -= 25) {
+                       ret = adv7511_irq_process(adv7511);
+                       if (ret < 0)
                                break;
+
+                       if (adv7511->edid_read)
+                               break;
+
                        msleep(25);
-                       timeout -= 25;
-               } while (timeout >= 25);
+               }
        }
 
-       return pending;
+       return adv7511->edid_read ? 0 : -EIO;
 }
 
-/* -----------------------------------------------------------------------------
- * EDID retrieval
- */
-
 static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block,
                                  size_t len)
 {
@@ -463,19 +508,14 @@ static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block,
                        return ret;
 
                if (status != 2) {
+                       adv7511->edid_read = false;
                        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;
+                       ret = adv7511_wait_for_edid(adv7511, 200);
+                       if (ret < 0)
+                               return ret;
                }
 
-               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
                 */
@@ -526,9 +566,11 @@ static int adv7511_get_modes(struct drm_encoder *encoder,
        unsigned int count;
 
        /* Reading the EDID only works if the device is powered */
-       if (adv7511->dpms_mode != DRM_MODE_DPMS_ON) {
+       if (!adv7511->powered) {
                regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
-                            ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR);
+                            ADV7511_INT0_EDID_READY);
+               regmap_write(adv7511->regmap, ADV7511_REG_INT(1),
+                            ADV7511_INT1_DDC_ERROR);
                regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
                                   ADV7511_POWER_POWER_DOWN, 0);
                adv7511->current_edid_segment = -1;
@@ -536,7 +578,7 @@ static int adv7511_get_modes(struct drm_encoder *encoder,
 
        edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511);
 
-       if (adv7511->dpms_mode != DRM_MODE_DPMS_ON)
+       if (!adv7511->powered)
                regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
                                   ADV7511_POWER_POWER_DOWN,
                                   ADV7511_POWER_POWER_DOWN);
@@ -558,41 +600,10 @@ 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 enabling 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;
+       if (mode == DRM_MODE_DPMS_ON)
+               adv7511_power_on(adv7511);
+       else
+               adv7511_power_off(adv7511);
 }
 
 static enum drm_connector_status
@@ -620,10 +631,9 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
         * 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) {
+       if (status == connector_status_connected && hpd && adv7511->powered) {
                regcache_mark_dirty(adv7511->regmap);
-               adv7511_encoder_dpms(encoder, adv7511->dpms_mode);
+               adv7511_power_on(adv7511);
                adv7511_get_modes(encoder, connector);
                if (adv7511->status == connector_status_connected)
                        status = connector_status_disconnected;
@@ -858,7 +868,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
        if (!adv7511)
                return -ENOMEM;
 
-       adv7511->dpms_mode = DRM_MODE_DPMS_OFF;
+       adv7511->powered = false;
        adv7511->status = connector_status_disconnected;
 
        ret = adv7511_parse_dt(dev->of_node, &link_config);
@@ -918,10 +928,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
        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;
+       adv7511_power_off(adv7511);
 
        i2c_set_clientdata(i2c, adv7511);
 
index e9ff6fc6126726a24bdf19e4f0f5b50adab8c0d5..a4c0a04b5044c22082851d4c3e8e28ba943d6b6f 100644 (file)
@@ -1113,7 +1113,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
        drm_modeset_lock_all(dev);
 
        plane = drm_plane_find(dev, set->plane_id);
-       if (!plane) {
+       if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) {
                ret = -ENOENT;
                goto out_unlock;
        }
index 33cdddf266849c00d29608317fd7b948436a0bf1..2b81a417cf291e11c78cbbc6672dbfed46aaaf28 100644 (file)
@@ -36,6 +36,7 @@ config DRM_IMX_TVE
 config DRM_IMX_LDB
        tristate "Support for LVDS displays"
        depends on DRM_IMX && MFD_SYSCON
+       select DRM_PANEL
        help
          Choose this to enable the internal LVDS Display Bridge (LDB)
          found on i.MX53 and i.MX6 processors.
index 87fe8ed92ebeb8bf996fb95b79731dbebdbed2dd..a3ecf1069b7637cd8a66574a9c61132923540d92 100644 (file)
@@ -75,10 +75,10 @@ static const struct dw_hdmi_curr_ctrl imx_cur_ctr[] = {
        },
 };
 
-static const struct dw_hdmi_sym_term imx_sym_term[] = {
-       /*pixelclk   symbol   term*/
-       { 148500000, 0x800d, 0x0005 },
-       { ~0UL,      0x0000, 0x0000 }
+static const struct dw_hdmi_phy_config imx_phy_config[] = {
+       /*pixelclk   symbol   term   vlev */
+       { 148500000, 0x800d, 0x0005, 0x01ad},
+       { ~0UL,      0x0000, 0x0000, 0x0000}
 };
 
 static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi)
@@ -123,7 +123,7 @@ static void dw_hdmi_imx_encoder_commit(struct drm_encoder *encoder)
 
 static void dw_hdmi_imx_encoder_prepare(struct drm_encoder *encoder)
 {
-       imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
+       imx_drm_set_bus_format(encoder, MEDIA_BUS_FMT_RGB888_1X24);
 }
 
 static struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = {
@@ -163,7 +163,7 @@ static enum drm_mode_status imx6dl_hdmi_mode_valid(struct drm_connector *con,
 static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
        .mpll_cfg   = imx_mpll_cfg,
        .cur_ctr    = imx_cur_ctr,
-       .sym_term   = imx_sym_term,
+       .phy_config = imx_phy_config,
        .dev_type   = IMX6Q_HDMI,
        .mode_valid = imx6q_hdmi_mode_valid,
 };
@@ -171,7 +171,7 @@ static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
 static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
        .mpll_cfg = imx_mpll_cfg,
        .cur_ctr  = imx_cur_ctr,
-       .sym_term = imx_sym_term,
+       .phy_config = imx_phy_config,
        .dev_type = IMX6DL_HDMI,
        .mode_valid = imx6dl_hdmi_mode_valid,
 };
index a002f53aab0e3a3654a722f218be7854ffb70cd4..74f505b0dd0280d47fcd9268e2b4d95a1ddae250 100644 (file)
@@ -103,8 +103,8 @@ static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
        return NULL;
 }
 
-int imx_drm_panel_format_pins(struct drm_encoder *encoder,
-               u32 interface_pix_fmt, int hsync_pin, int vsync_pin)
+int imx_drm_set_bus_format_pins(struct drm_encoder *encoder, u32 bus_format,
+               int hsync_pin, int vsync_pin)
 {
        struct imx_drm_crtc_helper_funcs *helper;
        struct imx_drm_crtc *imx_crtc;
@@ -116,16 +116,16 @@ int imx_drm_panel_format_pins(struct drm_encoder *encoder,
        helper = &imx_crtc->imx_drm_helper_funcs;
        if (helper->set_interface_pix_fmt)
                return helper->set_interface_pix_fmt(encoder->crtc,
-                               interface_pix_fmt, hsync_pin, vsync_pin);
+                                       bus_format, hsync_pin, vsync_pin);
        return 0;
 }
-EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins);
+EXPORT_SYMBOL_GPL(imx_drm_set_bus_format_pins);
 
-int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt)
+int imx_drm_set_bus_format(struct drm_encoder *encoder, u32 bus_format)
 {
-       return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3);
+       return imx_drm_set_bus_format_pins(encoder, bus_format, 2, 3);
 }
-EXPORT_SYMBOL_GPL(imx_drm_panel_format);
+EXPORT_SYMBOL_GPL(imx_drm_set_bus_format);
 
 int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
 {
@@ -431,15 +431,6 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
 
-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;
-}
-
 /*
  * @node: device tree node containing encoder input ports
  * @encoder: drm_encoder
@@ -448,7 +439,7 @@ 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 device_node *ep;
        struct of_endpoint endpoint;
        struct device_node *port;
        int ret;
@@ -456,18 +447,15 @@ int imx_drm_encoder_get_mux_id(struct device_node *node,
        if (!node || !imx_crtc)
                return -EINVAL;
 
-       do {
-               ep = imx_drm_of_get_next_endpoint(node, ep);
-               if (!ep)
-                       break;
-
+       for_each_endpoint_of_node(node, ep) {
                port = of_graph_get_remote_port(ep);
                of_node_put(port);
                if (port == imx_crtc->crtc->port) {
                        ret = of_graph_parse_endpoint(ep, &endpoint);
+                       of_node_put(ep);
                        return ret ? ret : endpoint.port;
                }
-       } while (ep);
+       }
 
        return -EINVAL;
 }
index 3c559ccd6af0042a73564041477cb0950674fe7f..28e776d8d9d270259f0df5b270897cdb8aec0e24 100644 (file)
@@ -18,7 +18,7 @@ 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 pix_fmt, int hsync_pin, int vsync_pin);
+                       u32 bus_format, int hsync_pin, int vsync_pin);
        const struct drm_crtc_helper_funcs *crtc_helper_funcs;
        const struct drm_crtc_funcs *crtc_funcs;
 };
@@ -40,10 +40,10 @@ 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_set_bus_format_pins(struct drm_encoder *encoder,
+               u32 bus_format, int hsync_pin, int vsync_pin);
+int imx_drm_set_bus_format(struct drm_encoder *encoder,
+               u32 bus_format);
 
 int imx_drm_encoder_get_mux_id(struct device_node *node,
                struct drm_encoder *encoder);
index 2d6dc94e1e64e973f61a1294c24bba6d2d788ae2..abacc8f674698c98c9444f12629f7895fcbe67a6 100644 (file)
 #include <drm/drmP.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_panel.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 <linux/of_graph.h>
 #include <video/of_videomode.h>
 #include <linux/regmap.h>
 #include <linux/videodev2.h>
@@ -55,12 +56,14 @@ struct imx_ldb_channel {
        struct imx_ldb *ldb;
        struct drm_connector connector;
        struct drm_encoder encoder;
+       struct drm_panel *panel;
        struct device_node *child;
        int chno;
        void *edid;
        int edid_len;
        struct drm_display_mode mode;
        int mode_valid;
+       int bus_format;
 };
 
 struct bus_mux {
@@ -75,6 +78,7 @@ struct imx_ldb {
        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_parent[4]; /* original parent of clk_sel */
        struct clk *clk_pll[2]; /* upstream clock we can adjust */
        u32 ldb_ctrl;
        const struct bus_mux *lvds_mux;
@@ -91,6 +95,17 @@ 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->panel && imx_ldb_ch->panel->funcs &&
+           imx_ldb_ch->panel->funcs->get_modes) {
+               struct drm_display_info *di = &connector->display_info;
+
+               num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel);
+               if (!imx_ldb_ch->bus_format && di->num_bus_formats)
+                       imx_ldb_ch->bus_format = di->bus_formats[0];
+               if (num_modes > 0)
+                       return num_modes;
+       }
+
        if (imx_ldb_ch->edid) {
                drm_mode_connector_update_edid_property(connector,
                                                        imx_ldb_ch->edid);
@@ -163,24 +178,36 @@ 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;
-       u32 pixel_fmt;
+       int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
+       u32 bus_format;
 
-       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;
+       switch (imx_ldb_ch->bus_format) {
+       default:
+               dev_warn(ldb->dev,
+                        "could not determine data mapping, default to 18-bit \"spwg\"\n");
+               /* fallthrough */
+       case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+               bus_format = MEDIA_BUS_FMT_RGB666_1X18;
                break;
-       case 1:
-               pixel_fmt = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH1_24) ?
-                       V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666;
+       case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
+               bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+               if (imx_ldb_ch->chno == 0 || dual)
+                       ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24;
+               if (imx_ldb_ch->chno == 1 || dual)
+                       ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24;
+               break;
+       case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
+               bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+               if (imx_ldb_ch->chno == 0 || dual)
+                       ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 |
+                                        LDB_BIT_MAP_CH0_JEIDA;
+               if (imx_ldb_ch->chno == 1 || dual)
+                       ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 |
+                                        LDB_BIT_MAP_CH1_JEIDA;
                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);
+       imx_drm_set_bus_format(encoder, bus_format);
 }
 
 static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
@@ -190,6 +217,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
        int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
        int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
 
+       drm_panel_prepare(imx_ldb_ch->panel);
+
        if (dual) {
                clk_prepare_enable(ldb->clk[0]);
                clk_prepare_enable(ldb->clk[1]);
@@ -223,6 +252,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
        }
 
        regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
+
+       drm_panel_enable(imx_ldb_ch->panel);
 }
 
 static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
@@ -274,6 +305,7 @@ 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;
+       int mux, ret;
 
        /*
         * imx_ldb_encoder_disable is called by
@@ -287,6 +319,8 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
                 (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0)
                return;
 
+       drm_panel_disable(imx_ldb_ch->panel);
+
        if (imx_ldb_ch == &ldb->channel[0])
                ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
        else if (imx_ldb_ch == &ldb->channel[1])
@@ -298,6 +332,30 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
                clk_disable_unprepare(ldb->clk[0]);
                clk_disable_unprepare(ldb->clk[1]);
        }
+
+       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_read(ldb->regmap, lvds_mux->reg, &mux);
+               mux &= lvds_mux->mask;
+               mux >>= lvds_mux->shift;
+       } else {
+               mux = (imx_ldb_ch == &ldb->channel[0]) ? 0 : 1;
+       }
+
+       /* set display clock mux back to original input clock */
+       ret = clk_set_parent(ldb->clk_sel[mux], ldb->clk_parent[mux]);
+       if (ret)
+               dev_err(ldb->dev,
+                       "unable to set di%d parent clock to original parent\n",
+                       mux);
+
+       drm_panel_unprepare(imx_ldb_ch->panel);
 }
 
 static struct drm_connector_funcs imx_ldb_connector_funcs = {
@@ -371,6 +429,9 @@ static int imx_ldb_register(struct drm_device *drm,
        drm_connector_init(drm, &imx_ldb_ch->connector,
                           &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
 
+       if (imx_ldb_ch->panel)
+               drm_panel_attach(imx_ldb_ch->panel, &imx_ldb_ch->connector);
+
        drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
                        &imx_ldb_ch->encoder);
 
@@ -382,25 +443,39 @@ enum {
        LVDS_BIT_MAP_JEIDA
 };
 
-static const char * const imx_ldb_bit_mappings[] = {
-       [LVDS_BIT_MAP_SPWG]  = "spwg",
-       [LVDS_BIT_MAP_JEIDA] = "jeida",
+struct imx_ldb_bit_mapping {
+       u32 bus_format;
+       u32 datawidth;
+       const char * const mapping;
+};
+
+static const struct imx_ldb_bit_mapping imx_ldb_bit_mappings[] = {
+       { MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,  18, "spwg" },
+       { MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,  24, "spwg" },
+       { MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 24, "jeida" },
 };
 
-static const int of_get_data_mapping(struct device_node *np)
+static u32 of_get_bus_format(struct device *dev, struct device_node *np)
 {
        const char *bm;
+       u32 datawidth = 0;
        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;
+       of_property_read_u32(np, "fsl,data-width", &datawidth);
 
-       return -EINVAL;
+       for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++) {
+               if (!strcasecmp(bm, imx_ldb_bit_mappings[i].mapping) &&
+                   datawidth == imx_ldb_bit_mappings[i].datawidth)
+                       return imx_ldb_bit_mappings[i].bus_format;
+       }
+
+       dev_err(dev, "invalid data mapping: %d-bit \"%s\"\n", datawidth, bm);
+
+       return -ENOENT;
 }
 
 static struct bus_mux imx6q_lvds_mux[2] = {
@@ -437,8 +512,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
        struct device_node *child;
        const u8 *edidp;
        struct imx_ldb *imx_ldb;
-       int datawidth;
-       int mapping;
        int dual;
        int ret;
        int i;
@@ -479,12 +552,15 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
                        imx_ldb->clk_sel[i] = NULL;
                        break;
                }
+
+               imx_ldb->clk_parent[i] = clk_get_parent(imx_ldb->clk_sel[i]);
        }
        if (i == 0)
                return ret;
 
        for_each_child_of_node(np, child) {
                struct imx_ldb_channel *channel;
+               struct device_node *port;
 
                ret = of_property_read_u32(child, "reg", &i);
                if (ret || i < 0 || i > 1)
@@ -503,49 +579,53 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
                channel->chno = i;
                channel->child = child;
 
+               /*
+                * The output port is port@4 with an external 4-port mux or
+                * port@2 with the internal 2-port mux.
+                */
+               port = of_graph_get_port_by_id(child, imx_ldb->lvds_mux ? 4 : 2);
+               if (port) {
+                       struct device_node *endpoint, *remote;
+
+                       endpoint = of_get_child_by_name(port, "endpoint");
+                       if (endpoint) {
+                               remote = of_graph_get_remote_port_parent(endpoint);
+                               if (remote)
+                                       channel->panel = of_drm_find_panel(remote);
+                               else
+                                       return -EPROBE_DEFER;
+                               if (!channel->panel) {
+                                       dev_err(dev, "panel not found: %s\n",
+                                               remote->full_name);
+                                       return -EPROBE_DEFER;
+                               }
+                       }
+               }
+
                edidp = of_get_property(child, "edid", &channel->edid_len);
                if (edidp) {
                        channel->edid = kmemdup(edidp, channel->edid_len,
                                                GFP_KERNEL);
-               } else {
+               } else if (!channel->panel) {
                        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;
+               channel->bus_format = of_get_bus_format(dev, child);
+               if (channel->bus_format == -EINVAL) {
+                       /*
+                        * If no bus format was specified in the device tree,
+                        * we can still get it from the connected panel later.
+                        */
+                       if (channel->panel && channel->panel->funcs &&
+                           channel->panel->funcs->get_modes)
+                               channel->bus_format = 0;
+               }
+               if (channel->bus_format < 0) {
+                       dev_err(dev, "could not determine data mapping: %d\n",
+                               channel->bus_format);
+                       return channel->bus_format;
                }
 
                ret = imx_ldb_register(drm, channel);
index 4216e479a9bed34e2f51b0dced03af1b1c3349d8..214eceefc981e4018b9aeb262ad2ebbc4b4abfa0 100644 (file)
@@ -301,11 +301,11 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder)
 
        switch (tve->mode) {
        case TVE_MODE_VGA:
-               imx_drm_panel_format_pins(encoder, IPU_PIX_FMT_GBR24,
-                               tve->hsync_pin, tve->vsync_pin);
+               imx_drm_set_bus_format_pins(encoder, MEDIA_BUS_FMT_YUV8_1X24,
+                                           tve->hsync_pin, tve->vsync_pin);
                break;
        case TVE_MODE_TVOUT:
-               imx_drm_panel_format(encoder, V4L2_PIX_FMT_YUV444);
+               imx_drm_set_bus_format(encoder, MEDIA_BUS_FMT_YUV8_1X24);
                break;
        }
 }
index 98551e356e12a4d2c2fdbff21b00a4e22e8b4f3f..7bc8301faffffff69194f20ca9d64b8e398f6478 100644 (file)
@@ -45,7 +45,7 @@ struct ipu_crtc {
        struct drm_pending_vblank_event *page_flip_event;
        struct drm_framebuffer  *newfb;
        int                     irq;
-       u32                     interface_pix_fmt;
+       u32                     bus_format;
        int                     di_hsync_pin;
        int                     di_vsync_pin;
 };
@@ -145,7 +145,6 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
        struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
        struct ipu_di_signal_cfg sig_cfg = {};
        unsigned long encoder_types = 0;
-       u32 out_pixel_fmt;
        int ret;
 
        dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__,
@@ -161,21 +160,21 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
                __func__, encoder_types);
 
        /*
-        * If we have DAC, TVDAC or LDB, then we need the IPU DI clock
-        * to be the same as the LDB DI clock.
+        * If we have DAC or LDB, then we need the IPU DI clock to be
+        * the same as the LDB DI clock. For TVDAC, derive the IPU DI
+        * clock from 27 MHz TVE_DI clock, but allow to divide it.
         */
        if (encoder_types & (BIT(DRM_MODE_ENCODER_DAC) |
-                            BIT(DRM_MODE_ENCODER_TVDAC) |
                             BIT(DRM_MODE_ENCODER_LVDS)))
                sig_cfg.clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT;
+       else if (encoder_types & BIT(DRM_MODE_ENCODER_TVDAC))
+               sig_cfg.clkflags = IPU_DI_CLKMODE_EXT;
        else
                sig_cfg.clkflags = 0;
 
-       out_pixel_fmt = ipu_crtc->interface_pix_fmt;
-
        sig_cfg.enable_pol = 1;
        sig_cfg.clk_pol = 0;
-       sig_cfg.pixel_fmt = out_pixel_fmt;
+       sig_cfg.bus_format = ipu_crtc->bus_format;
        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;
@@ -184,7 +183,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
 
        ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di,
                               mode->flags & DRM_MODE_FLAG_INTERLACE,
-                              out_pixel_fmt, mode->hdisplay);
+                              ipu_crtc->bus_format, mode->hdisplay);
        if (ret) {
                dev_err(ipu_crtc->dev,
                                "initializing display controller failed with %d\n",
@@ -202,7 +201,8 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
        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);
+                                 x, y, mode->hdisplay, mode->vdisplay,
+                                 mode->flags & DRM_MODE_FLAG_INTERLACE);
 }
 
 static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc)
@@ -291,11 +291,11 @@ static void ipu_disable_vblank(struct drm_crtc *crtc)
 }
 
 static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc,
-               u32 pixfmt, int hsync_pin, int vsync_pin)
+               u32 bus_format, int hsync_pin, int vsync_pin)
 {
        struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
 
-       ipu_crtc->interface_pix_fmt = pixfmt;
+       ipu_crtc->bus_format = bus_format;
        ipu_crtc->di_hsync_pin = hsync_pin;
        ipu_crtc->di_vsync_pin = vsync_pin;
 
index 6987e16fe99b03f507307beddbe2ed228d603b8d..878a643d72e4c1cc7f9bbba257d88719b4b0703f 100644 (file)
@@ -99,7 +99,7 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_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 src_w, uint32_t src_h, bool interlaced)
 {
        struct device *dev = ipu_plane->base.dev->dev;
        int ret;
@@ -213,6 +213,8 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
        ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
        if (ret < 0)
                return ret;
+       if (interlaced)
+               ipu_cpmem_interlaced_scan(ipu_plane->ipu_ch, fb->pitches[0]);
 
        ipu_plane->w = src_w;
        ipu_plane->h = src_h;
@@ -312,7 +314,8 @@ static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 
        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);
+                       src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16,
+                       false);
        if (ret < 0) {
                ipu_plane_put_resources(ipu_plane);
                return ret;
index af125fb40ef5c03736a94f2b98968f9cf9a87426..9b5eff18f5b826b722d97b8e763dbd3017197aee 100644 (file)
@@ -42,7 +42,7 @@ int ipu_plane_mode_set(struct ipu_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 src_h, bool interlaced);
 
 void ipu_plane_enable(struct ipu_plane *plane);
 void ipu_plane_disable(struct ipu_plane *plane);
index 900dda6a8e71b5501293b8d4be06ddb8288dee27..74a9ce40ddc457f476611478d87f14ec2f67d8fd 100644 (file)
@@ -33,7 +33,7 @@ struct imx_parallel_display {
        struct device *dev;
        void *edid;
        int edid_len;
-       u32 interface_pix_fmt;
+       u32 bus_format;
        int mode_valid;
        struct drm_display_mode mode;
        struct drm_panel *panel;
@@ -118,7 +118,7 @@ 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);
+       imx_drm_set_bus_format(encoder, imxpd->bus_format);
 }
 
 static void imx_pd_encoder_commit(struct drm_encoder *encoder)
@@ -225,14 +225,13 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
        ret = of_property_read_string(np, "interface-pix-fmt", &fmt);
        if (!ret) {
                if (!strcmp(fmt, "rgb24"))
-                       imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB24;
+                       imxpd->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
                else if (!strcmp(fmt, "rgb565"))
-                       imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565;
+                       imxpd->bus_format = MEDIA_BUS_FMT_RGB565_1X16;
                else if (!strcmp(fmt, "bgr666"))
-                       imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666;
+                       imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X18;
                else if (!strcmp(fmt, "lvds666"))
-                       imxpd->interface_pix_fmt =
-                                       v4l2_fourcc('L', 'V', 'D', '6');
+                       imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI;
        }
 
        panel_node = of_parse_phandle(np, "fsl,panel", 0);
index 9872ba9abf1a28e4bdf3625e596c41a862fec291..6e84df9369a657223d17387ad14929cdf435e238 100644 (file)
@@ -1222,7 +1222,7 @@ static void mga_crtc_commit(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct mga_device *mdev = dev->dev_private;
-       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+       const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
        u8 tmp;
 
        if (mdev->type == G200_WB)
index bacbbb70f679a45d1cbe70ec631c19d0be807e4f..0a6f6764a37c26e192e667f3a9bb62d3d14d5ad7 100644 (file)
@@ -35,3 +35,14 @@ config DRM_MSM_REGISTER_LOGGING
          Compile in support for logging register reads/writes in a format
          that can be parsed by envytools demsm tool.  If enabled, register
          logging can be switched on via msm.reglog=y module param.
+
+config DRM_MSM_DSI
+       bool "Enable DSI support in MSM DRM driver"
+       depends on DRM_MSM
+       select DRM_PANEL
+       select DRM_MIPI_DSI
+       default y
+       help
+         Choose this option if you have a need for MIPI DSI connector
+         support.
+
index 674a132fd76e1373e6be33178ba46413a20c6de0..ab2086783feec509fa982c477cd8de504447ae72 100644 (file)
@@ -50,5 +50,10 @@ msm-y := \
 
 msm-$(CONFIG_DRM_MSM_FBDEV) += msm_fbdev.o
 msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o
+msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \
+                       dsi/dsi_host.o \
+                       dsi/dsi_manager.o \
+                       dsi/dsi_phy.o \
+                       mdp/mdp5/mdp5_cmd_encoder.o
 
 obj-$(CONFIG_DRM_MSM)  += msm.o
diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
new file mode 100644 (file)
index 0000000..28d1f95
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2015, 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 "dsi.h"
+
+struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
+{
+       if (!msm_dsi || !msm_dsi->panel)
+               return NULL;
+
+       return (msm_dsi->panel_flags & MIPI_DSI_MODE_VIDEO) ?
+               msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID] :
+               msm_dsi->encoders[MSM_DSI_CMD_ENCODER_ID];
+}
+
+static void dsi_destroy(struct msm_dsi *msm_dsi)
+{
+       if (!msm_dsi)
+               return;
+
+       msm_dsi_manager_unregister(msm_dsi);
+       if (msm_dsi->host) {
+               msm_dsi_host_destroy(msm_dsi->host);
+               msm_dsi->host = NULL;
+       }
+
+       platform_set_drvdata(msm_dsi->pdev, NULL);
+}
+
+static struct msm_dsi *dsi_init(struct platform_device *pdev)
+{
+       struct msm_dsi *msm_dsi = NULL;
+       int ret;
+
+       if (!pdev) {
+               dev_err(&pdev->dev, "no dsi device\n");
+               ret = -ENXIO;
+               goto fail;
+       }
+
+       msm_dsi = devm_kzalloc(&pdev->dev, sizeof(*msm_dsi), GFP_KERNEL);
+       if (!msm_dsi) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+       DBG("dsi probed=%p", msm_dsi);
+
+       msm_dsi->pdev = pdev;
+       platform_set_drvdata(pdev, msm_dsi);
+
+       /* Init dsi host */
+       ret = msm_dsi_host_init(msm_dsi);
+       if (ret)
+               goto fail;
+
+       /* Register to dsi manager */
+       ret = msm_dsi_manager_register(msm_dsi);
+       if (ret)
+               goto fail;
+
+       return msm_dsi;
+
+fail:
+       if (msm_dsi)
+               dsi_destroy(msm_dsi);
+
+       return ERR_PTR(ret);
+}
+
+static int dsi_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;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct msm_dsi *msm_dsi;
+
+       DBG("");
+       msm_dsi = dsi_init(pdev);
+       if (IS_ERR(msm_dsi))
+               return PTR_ERR(msm_dsi);
+
+       priv->dsi[msm_dsi->id] = msm_dsi;
+
+       return 0;
+}
+
+static void dsi_unbind(struct device *dev, struct device *master,
+               void *data)
+{
+       struct drm_device *drm = dev_get_drvdata(master);
+       struct msm_drm_private *priv = drm->dev_private;
+       struct msm_dsi *msm_dsi = dev_get_drvdata(dev);
+       int id = msm_dsi->id;
+
+       if (priv->dsi[id]) {
+               dsi_destroy(msm_dsi);
+               priv->dsi[id] = NULL;
+       }
+}
+
+static const struct component_ops dsi_ops = {
+       .bind   = dsi_bind,
+       .unbind = dsi_unbind,
+};
+
+static int dsi_dev_probe(struct platform_device *pdev)
+{
+       return component_add(&pdev->dev, &dsi_ops);
+}
+
+static int dsi_dev_remove(struct platform_device *pdev)
+{
+       DBG("");
+       component_del(&pdev->dev, &dsi_ops);
+       return 0;
+}
+
+static const struct of_device_id dt_match[] = {
+       { .compatible = "qcom,mdss-dsi-ctrl" },
+       {}
+};
+
+static struct platform_driver dsi_driver = {
+       .probe = dsi_dev_probe,
+       .remove = dsi_dev_remove,
+       .driver = {
+               .name = "msm_dsi",
+               .of_match_table = dt_match,
+       },
+};
+
+void __init msm_dsi_register(void)
+{
+       DBG("");
+       platform_driver_register(&dsi_driver);
+}
+
+void __exit msm_dsi_unregister(void)
+{
+       DBG("");
+       platform_driver_unregister(&dsi_driver);
+}
+
+int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
+               struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM])
+{
+       struct msm_drm_private *priv = dev->dev_private;
+       int ret, i;
+
+       if (WARN_ON(!encoders[MSM_DSI_VIDEO_ENCODER_ID] ||
+               !encoders[MSM_DSI_CMD_ENCODER_ID]))
+               return -EINVAL;
+
+       msm_dsi->dev = dev;
+
+       ret = msm_dsi_host_modeset_init(msm_dsi->host, dev);
+       if (ret) {
+               dev_err(dev->dev, "failed to modeset init host: %d\n", ret);
+               goto fail;
+       }
+
+       msm_dsi->bridge = msm_dsi_manager_bridge_init(msm_dsi->id);
+       if (IS_ERR(msm_dsi->bridge)) {
+               ret = PTR_ERR(msm_dsi->bridge);
+               dev_err(dev->dev, "failed to create dsi bridge: %d\n", ret);
+               msm_dsi->bridge = NULL;
+               goto fail;
+       }
+
+       msm_dsi->connector = msm_dsi_manager_connector_init(msm_dsi->id);
+       if (IS_ERR(msm_dsi->connector)) {
+               ret = PTR_ERR(msm_dsi->connector);
+               dev_err(dev->dev, "failed to create dsi connector: %d\n", ret);
+               msm_dsi->connector = NULL;
+               goto fail;
+       }
+
+       for (i = 0; i < MSM_DSI_ENCODER_NUM; i++) {
+               encoders[i]->bridge = msm_dsi->bridge;
+               msm_dsi->encoders[i] = encoders[i];
+       }
+
+       priv->bridges[priv->num_bridges++]       = msm_dsi->bridge;
+       priv->connectors[priv->num_connectors++] = msm_dsi->connector;
+
+       return 0;
+fail:
+       if (msm_dsi) {
+               /* bridge/connector are normally destroyed by drm: */
+               if (msm_dsi->bridge) {
+                       msm_dsi_manager_bridge_destroy(msm_dsi->bridge);
+                       msm_dsi->bridge = NULL;
+               }
+               if (msm_dsi->connector) {
+                       msm_dsi->connector->funcs->destroy(msm_dsi->connector);
+                       msm_dsi->connector = NULL;
+               }
+       }
+
+       return ret;
+}
+
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
new file mode 100644 (file)
index 0000000..10f54d4
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2015, 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 __DSI_CONNECTOR_H__
+#define __DSI_CONNECTOR_H__
+
+#include <linux/platform_device.h>
+
+#include "drm_crtc.h"
+#include "drm_mipi_dsi.h"
+#include "drm_panel.h"
+
+#include "msm_drv.h"
+
+#define DSI_0  0
+#define DSI_1  1
+#define DSI_MAX        2
+
+#define DSI_CLOCK_MASTER       DSI_0
+#define DSI_CLOCK_SLAVE                DSI_1
+
+#define DSI_LEFT               DSI_0
+#define DSI_RIGHT              DSI_1
+
+/* According to the current drm framework sequence, take the encoder of
+ * DSI_1 as master encoder
+ */
+#define DSI_ENCODER_MASTER     DSI_1
+#define DSI_ENCODER_SLAVE      DSI_0
+
+struct msm_dsi {
+       struct drm_device *dev;
+       struct platform_device *pdev;
+
+       struct drm_connector *connector;
+       struct drm_bridge *bridge;
+
+       struct mipi_dsi_host *host;
+       struct msm_dsi_phy *phy;
+       struct drm_panel *panel;
+       unsigned long panel_flags;
+       bool phy_enabled;
+
+       /* the encoders we are hooked to (outside of dsi block) */
+       struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM];
+
+       int id;
+};
+
+/* dsi manager */
+struct drm_bridge *msm_dsi_manager_bridge_init(u8 id);
+void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge);
+struct drm_connector *msm_dsi_manager_connector_init(u8 id);
+int msm_dsi_manager_phy_enable(int id,
+               const unsigned long bit_rate, const unsigned long esc_rate,
+               u32 *clk_pre, u32 *clk_post);
+void msm_dsi_manager_phy_disable(int id);
+int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
+bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len);
+int msm_dsi_manager_register(struct msm_dsi *msm_dsi);
+void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi);
+
+/* msm dsi */
+struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
+
+/* dsi host */
+int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
+                                       const struct mipi_dsi_msg *msg);
+void msm_dsi_host_xfer_restore(struct mipi_dsi_host *host,
+                                       const struct mipi_dsi_msg *msg);
+int msm_dsi_host_cmd_tx(struct mipi_dsi_host *host,
+                                       const struct mipi_dsi_msg *msg);
+int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host,
+                                       const struct mipi_dsi_msg *msg);
+void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host,
+                                       u32 iova, u32 len);
+int msm_dsi_host_enable(struct mipi_dsi_host *host);
+int msm_dsi_host_disable(struct mipi_dsi_host *host);
+int msm_dsi_host_power_on(struct mipi_dsi_host *host);
+int msm_dsi_host_power_off(struct mipi_dsi_host *host);
+int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
+                                       struct drm_display_mode *mode);
+struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host,
+                                       unsigned long *panel_flags);
+int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer);
+void msm_dsi_host_unregister(struct mipi_dsi_host *host);
+void msm_dsi_host_destroy(struct mipi_dsi_host *host);
+int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
+                                       struct drm_device *dev);
+int msm_dsi_host_init(struct msm_dsi *msm_dsi);
+
+/* dsi phy */
+struct msm_dsi_phy;
+enum msm_dsi_phy_type {
+       MSM_DSI_PHY_UNKNOWN,
+       MSM_DSI_PHY_28NM,
+       MSM_DSI_PHY_MAX
+};
+struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev,
+                       enum msm_dsi_phy_type type, int id);
+int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
+       const unsigned long bit_rate, const unsigned long esc_rate);
+int msm_dsi_phy_disable(struct msm_dsi_phy *phy);
+void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy,
+                                       u32 *clk_pre, u32 *clk_post);
+#endif /* __DSI_CONNECTOR_H__ */
+
index abf1bba520bf25d24ba27b078cc55a44890f0037..1dcfae265e984723f6843fe93461796663e220e6 100644 (file)
@@ -8,19 +8,10 @@ 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/msm.xml                 (    676 bytes, from 2014-12-05 15:34:49)
-- /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            (  20908 bytes, from 2014-12-08 16:13:00)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2014-12-08 16:13:00)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  27208 bytes, from 2015-01-13 23:56:11)
-- /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-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           (  26848 bytes, from 2015-01-13 23:55:57)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (   8253 bytes, from 2014-12-08 16:13:00)
-
-Copyright (C) 2013 by the following authors:
+- /usr2/hali/local/envytools/envytools/rnndb/dsi/dsi.xml             (  18681 bytes, from 2015-03-04 23:08:31)
+- /usr2/hali/local/envytools/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2015-01-28 21:43:22)
+
+Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
 
 Permission is hereby granted, free of charge, to any person obtaining
@@ -51,11 +42,11 @@ enum dsi_traffic_mode {
        BURST_MODE = 2,
 };
 
-enum dsi_dst_format {
-       DST_FORMAT_RGB565 = 0,
-       DST_FORMAT_RGB666 = 1,
-       DST_FORMAT_RGB666_LOOSE = 2,
-       DST_FORMAT_RGB888 = 3,
+enum dsi_vid_dst_format {
+       VID_DST_FORMAT_RGB565 = 0,
+       VID_DST_FORMAT_RGB666 = 1,
+       VID_DST_FORMAT_RGB666_LOOSE = 2,
+       VID_DST_FORMAT_RGB888 = 3,
 };
 
 enum dsi_rgb_swap {
@@ -69,20 +60,63 @@ enum dsi_rgb_swap {
 
 enum dsi_cmd_trigger {
        TRIGGER_NONE = 0,
+       TRIGGER_SEOF = 1,
        TRIGGER_TE = 2,
        TRIGGER_SW = 4,
        TRIGGER_SW_SEOF = 5,
        TRIGGER_SW_TE = 6,
 };
 
+enum dsi_cmd_dst_format {
+       CMD_DST_FORMAT_RGB111 = 0,
+       CMD_DST_FORMAT_RGB332 = 3,
+       CMD_DST_FORMAT_RGB444 = 4,
+       CMD_DST_FORMAT_RGB565 = 6,
+       CMD_DST_FORMAT_RGB666 = 7,
+       CMD_DST_FORMAT_RGB888 = 8,
+};
+
+enum dsi_lane_swap {
+       LANE_SWAP_0123 = 0,
+       LANE_SWAP_3012 = 1,
+       LANE_SWAP_2301 = 2,
+       LANE_SWAP_1230 = 3,
+       LANE_SWAP_0321 = 4,
+       LANE_SWAP_1032 = 5,
+       LANE_SWAP_2103 = 6,
+       LANE_SWAP_3210 = 7,
+};
+
 #define DSI_IRQ_CMD_DMA_DONE                                   0x00000001
 #define DSI_IRQ_MASK_CMD_DMA_DONE                              0x00000002
 #define DSI_IRQ_CMD_MDP_DONE                                   0x00000100
 #define DSI_IRQ_MASK_CMD_MDP_DONE                              0x00000200
 #define DSI_IRQ_VIDEO_DONE                                     0x00010000
 #define DSI_IRQ_MASK_VIDEO_DONE                                        0x00020000
+#define DSI_IRQ_BTA_DONE                                       0x00100000
+#define DSI_IRQ_MASK_BTA_DONE                                  0x00200000
 #define DSI_IRQ_ERROR                                          0x01000000
 #define DSI_IRQ_MASK_ERROR                                     0x02000000
+#define REG_DSI_6G_HW_VERSION                                  0x00000000
+#define DSI_6G_HW_VERSION_MAJOR__MASK                          0xf0000000
+#define DSI_6G_HW_VERSION_MAJOR__SHIFT                         28
+static inline uint32_t DSI_6G_HW_VERSION_MAJOR(uint32_t val)
+{
+       return ((val) << DSI_6G_HW_VERSION_MAJOR__SHIFT) & DSI_6G_HW_VERSION_MAJOR__MASK;
+}
+#define DSI_6G_HW_VERSION_MINOR__MASK                          0x0fff0000
+#define DSI_6G_HW_VERSION_MINOR__SHIFT                         16
+static inline uint32_t DSI_6G_HW_VERSION_MINOR(uint32_t val)
+{
+       return ((val) << DSI_6G_HW_VERSION_MINOR__SHIFT) & DSI_6G_HW_VERSION_MINOR__MASK;
+}
+#define DSI_6G_HW_VERSION_STEP__MASK                           0x0000ffff
+#define DSI_6G_HW_VERSION_STEP__SHIFT                          0
+static inline uint32_t DSI_6G_HW_VERSION_STEP(uint32_t val)
+{
+       return ((val) << DSI_6G_HW_VERSION_STEP__SHIFT) & DSI_6G_HW_VERSION_STEP__MASK;
+}
+
 #define REG_DSI_CTRL                                           0x00000000
 #define DSI_CTRL_ENABLE                                                0x00000001
 #define DSI_CTRL_VID_MODE_EN                                   0x00000002
@@ -96,11 +130,15 @@ enum dsi_cmd_trigger {
 #define DSI_CTRL_CRC_CHECK                                     0x01000000
 
 #define REG_DSI_STATUS0                                                0x00000004
+#define DSI_STATUS0_CMD_MODE_ENGINE_BUSY                       0x00000001
 #define DSI_STATUS0_CMD_MODE_DMA_BUSY                          0x00000002
+#define DSI_STATUS0_CMD_MODE_MDP_BUSY                          0x00000004
 #define DSI_STATUS0_VIDEO_MODE_ENGINE_BUSY                     0x00000008
 #define DSI_STATUS0_DSI_BUSY                                   0x00000010
+#define DSI_STATUS0_INTERLEAVE_OP_CONTENTION                   0x80000000
 
 #define REG_DSI_FIFO_STATUS                                    0x00000008
+#define DSI_FIFO_STATUS_CMD_MDP_FIFO_UNDERFLOW                 0x00000080
 
 #define REG_DSI_VID_CFG0                                       0x0000000c
 #define DSI_VID_CFG0_VIRT_CHANNEL__MASK                                0x00000003
@@ -111,7 +149,7 @@ static inline uint32_t DSI_VID_CFG0_VIRT_CHANNEL(uint32_t val)
 }
 #define DSI_VID_CFG0_DST_FORMAT__MASK                          0x00000030
 #define DSI_VID_CFG0_DST_FORMAT__SHIFT                         4
-static inline uint32_t DSI_VID_CFG0_DST_FORMAT(enum dsi_dst_format val)
+static inline uint32_t DSI_VID_CFG0_DST_FORMAT(enum dsi_vid_dst_format val)
 {
        return ((val) << DSI_VID_CFG0_DST_FORMAT__SHIFT) & DSI_VID_CFG0_DST_FORMAT__MASK;
 }
@@ -129,21 +167,15 @@ static inline uint32_t DSI_VID_CFG0_TRAFFIC_MODE(enum dsi_traffic_mode val)
 #define DSI_VID_CFG0_PULSE_MODE_HSA_HE                         0x10000000
 
 #define REG_DSI_VID_CFG1                                       0x0000001c
-#define DSI_VID_CFG1_R_SEL                                     0x00000010
-#define DSI_VID_CFG1_G_SEL                                     0x00000100
-#define DSI_VID_CFG1_B_SEL                                     0x00001000
-#define DSI_VID_CFG1_RGB_SWAP__MASK                            0x00070000
-#define DSI_VID_CFG1_RGB_SWAP__SHIFT                           16
+#define DSI_VID_CFG1_R_SEL                                     0x00000001
+#define DSI_VID_CFG1_G_SEL                                     0x00000010
+#define DSI_VID_CFG1_B_SEL                                     0x00000100
+#define DSI_VID_CFG1_RGB_SWAP__MASK                            0x00007000
+#define DSI_VID_CFG1_RGB_SWAP__SHIFT                           12
 static inline uint32_t DSI_VID_CFG1_RGB_SWAP(enum dsi_rgb_swap val)
 {
        return ((val) << DSI_VID_CFG1_RGB_SWAP__SHIFT) & DSI_VID_CFG1_RGB_SWAP__MASK;
 }
-#define DSI_VID_CFG1_INTERLEAVE_MAX__MASK                      0x00f00000
-#define DSI_VID_CFG1_INTERLEAVE_MAX__SHIFT                     20
-static inline uint32_t DSI_VID_CFG1_INTERLEAVE_MAX(uint32_t val)
-{
-       return ((val) << DSI_VID_CFG1_INTERLEAVE_MAX__SHIFT) & DSI_VID_CFG1_INTERLEAVE_MAX__MASK;
-}
 
 #define REG_DSI_ACTIVE_H                                       0x00000020
 #define DSI_ACTIVE_H_START__MASK                               0x00000fff
@@ -201,32 +233,115 @@ static inline uint32_t DSI_ACTIVE_HSYNC_END(uint32_t val)
        return ((val) << DSI_ACTIVE_HSYNC_END__SHIFT) & DSI_ACTIVE_HSYNC_END__MASK;
 }
 
-#define REG_DSI_ACTIVE_VSYNC                                   0x00000034
-#define DSI_ACTIVE_VSYNC_START__MASK                           0x00000fff
-#define DSI_ACTIVE_VSYNC_START__SHIFT                          0
-static inline uint32_t DSI_ACTIVE_VSYNC_START(uint32_t val)
+#define REG_DSI_ACTIVE_VSYNC_HPOS                              0x00000030
+#define DSI_ACTIVE_VSYNC_HPOS_START__MASK                      0x00000fff
+#define DSI_ACTIVE_VSYNC_HPOS_START__SHIFT                     0
+static inline uint32_t DSI_ACTIVE_VSYNC_HPOS_START(uint32_t val)
 {
-       return ((val) << DSI_ACTIVE_VSYNC_START__SHIFT) & DSI_ACTIVE_VSYNC_START__MASK;
+       return ((val) << DSI_ACTIVE_VSYNC_HPOS_START__SHIFT) & DSI_ACTIVE_VSYNC_HPOS_START__MASK;
 }
-#define DSI_ACTIVE_VSYNC_END__MASK                             0x0fff0000
-#define DSI_ACTIVE_VSYNC_END__SHIFT                            16
-static inline uint32_t DSI_ACTIVE_VSYNC_END(uint32_t val)
+#define DSI_ACTIVE_VSYNC_HPOS_END__MASK                                0x0fff0000
+#define DSI_ACTIVE_VSYNC_HPOS_END__SHIFT                       16
+static inline uint32_t DSI_ACTIVE_VSYNC_HPOS_END(uint32_t val)
 {
-       return ((val) << DSI_ACTIVE_VSYNC_END__SHIFT) & DSI_ACTIVE_VSYNC_END__MASK;
+       return ((val) << DSI_ACTIVE_VSYNC_HPOS_END__SHIFT) & DSI_ACTIVE_VSYNC_HPOS_END__MASK;
+}
+
+#define REG_DSI_ACTIVE_VSYNC_VPOS                              0x00000034
+#define DSI_ACTIVE_VSYNC_VPOS_START__MASK                      0x00000fff
+#define DSI_ACTIVE_VSYNC_VPOS_START__SHIFT                     0
+static inline uint32_t DSI_ACTIVE_VSYNC_VPOS_START(uint32_t val)
+{
+       return ((val) << DSI_ACTIVE_VSYNC_VPOS_START__SHIFT) & DSI_ACTIVE_VSYNC_VPOS_START__MASK;
+}
+#define DSI_ACTIVE_VSYNC_VPOS_END__MASK                                0x0fff0000
+#define DSI_ACTIVE_VSYNC_VPOS_END__SHIFT                       16
+static inline uint32_t DSI_ACTIVE_VSYNC_VPOS_END(uint32_t val)
+{
+       return ((val) << DSI_ACTIVE_VSYNC_VPOS_END__SHIFT) & DSI_ACTIVE_VSYNC_VPOS_END__MASK;
 }
 
 #define REG_DSI_CMD_DMA_CTRL                                   0x00000038
+#define DSI_CMD_DMA_CTRL_BROADCAST_EN                          0x80000000
 #define DSI_CMD_DMA_CTRL_FROM_FRAME_BUFFER                     0x10000000
 #define DSI_CMD_DMA_CTRL_LOW_POWER                             0x04000000
 
 #define REG_DSI_CMD_CFG0                                       0x0000003c
+#define DSI_CMD_CFG0_DST_FORMAT__MASK                          0x0000000f
+#define DSI_CMD_CFG0_DST_FORMAT__SHIFT                         0
+static inline uint32_t DSI_CMD_CFG0_DST_FORMAT(enum dsi_cmd_dst_format val)
+{
+       return ((val) << DSI_CMD_CFG0_DST_FORMAT__SHIFT) & DSI_CMD_CFG0_DST_FORMAT__MASK;
+}
+#define DSI_CMD_CFG0_R_SEL                                     0x00000010
+#define DSI_CMD_CFG0_G_SEL                                     0x00000100
+#define DSI_CMD_CFG0_B_SEL                                     0x00001000
+#define DSI_CMD_CFG0_INTERLEAVE_MAX__MASK                      0x00f00000
+#define DSI_CMD_CFG0_INTERLEAVE_MAX__SHIFT                     20
+static inline uint32_t DSI_CMD_CFG0_INTERLEAVE_MAX(uint32_t val)
+{
+       return ((val) << DSI_CMD_CFG0_INTERLEAVE_MAX__SHIFT) & DSI_CMD_CFG0_INTERLEAVE_MAX__MASK;
+}
+#define DSI_CMD_CFG0_RGB_SWAP__MASK                            0x00070000
+#define DSI_CMD_CFG0_RGB_SWAP__SHIFT                           16
+static inline uint32_t DSI_CMD_CFG0_RGB_SWAP(enum dsi_rgb_swap val)
+{
+       return ((val) << DSI_CMD_CFG0_RGB_SWAP__SHIFT) & DSI_CMD_CFG0_RGB_SWAP__MASK;
+}
 
 #define REG_DSI_CMD_CFG1                                       0x00000040
+#define DSI_CMD_CFG1_WR_MEM_START__MASK                                0x000000ff
+#define DSI_CMD_CFG1_WR_MEM_START__SHIFT                       0
+static inline uint32_t DSI_CMD_CFG1_WR_MEM_START(uint32_t val)
+{
+       return ((val) << DSI_CMD_CFG1_WR_MEM_START__SHIFT) & DSI_CMD_CFG1_WR_MEM_START__MASK;
+}
+#define DSI_CMD_CFG1_WR_MEM_CONTINUE__MASK                     0x0000ff00
+#define DSI_CMD_CFG1_WR_MEM_CONTINUE__SHIFT                    8
+static inline uint32_t DSI_CMD_CFG1_WR_MEM_CONTINUE(uint32_t val)
+{
+       return ((val) << DSI_CMD_CFG1_WR_MEM_CONTINUE__SHIFT) & DSI_CMD_CFG1_WR_MEM_CONTINUE__MASK;
+}
+#define DSI_CMD_CFG1_INSERT_DCS_COMMAND                                0x00010000
 
 #define REG_DSI_DMA_BASE                                       0x00000044
 
 #define REG_DSI_DMA_LEN                                                0x00000048
 
+#define REG_DSI_CMD_MDP_STREAM_CTRL                            0x00000054
+#define DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE__MASK                        0x0000003f
+#define DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE__SHIFT               0
+static inline uint32_t DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE(uint32_t val)
+{
+       return ((val) << DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE__SHIFT) & DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE__MASK;
+}
+#define DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL__MASK          0x00000300
+#define DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL__SHIFT         8
+static inline uint32_t DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL(uint32_t val)
+{
+       return ((val) << DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL__SHIFT) & DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL__MASK;
+}
+#define DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT__MASK               0xffff0000
+#define DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT__SHIFT              16
+static inline uint32_t DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT(uint32_t val)
+{
+       return ((val) << DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT__SHIFT) & DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT__MASK;
+}
+
+#define REG_DSI_CMD_MDP_STREAM_TOTAL                           0x00000058
+#define DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL__MASK                 0x00000fff
+#define DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL__SHIFT                        0
+static inline uint32_t DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL(uint32_t val)
+{
+       return ((val) << DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL__SHIFT) & DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL__MASK;
+}
+#define DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL__MASK                 0x0fff0000
+#define DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL__SHIFT                        16
+static inline uint32_t DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL(uint32_t val)
+{
+       return ((val) << DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL__SHIFT) & DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL__MASK;
+}
+
 #define REG_DSI_ACK_ERR_STATUS                                 0x00000064
 
 static inline uint32_t REG_DSI_RDBK(uint32_t i0) { return 0x00000068 + 0x4*i0; }
@@ -234,19 +349,25 @@ static inline uint32_t REG_DSI_RDBK(uint32_t i0) { return 0x00000068 + 0x4*i0; }
 static inline uint32_t REG_DSI_RDBK_DATA(uint32_t i0) { return 0x00000068 + 0x4*i0; }
 
 #define REG_DSI_TRIG_CTRL                                      0x00000080
-#define DSI_TRIG_CTRL_DMA_TRIGGER__MASK                                0x0000000f
+#define DSI_TRIG_CTRL_DMA_TRIGGER__MASK                                0x00000007
 #define DSI_TRIG_CTRL_DMA_TRIGGER__SHIFT                       0
 static inline uint32_t DSI_TRIG_CTRL_DMA_TRIGGER(enum dsi_cmd_trigger val)
 {
        return ((val) << DSI_TRIG_CTRL_DMA_TRIGGER__SHIFT) & DSI_TRIG_CTRL_DMA_TRIGGER__MASK;
 }
-#define DSI_TRIG_CTRL_MDP_TRIGGER__MASK                                0x000000f0
+#define DSI_TRIG_CTRL_MDP_TRIGGER__MASK                                0x00000070
 #define DSI_TRIG_CTRL_MDP_TRIGGER__SHIFT                       4
 static inline uint32_t DSI_TRIG_CTRL_MDP_TRIGGER(enum dsi_cmd_trigger val)
 {
        return ((val) << DSI_TRIG_CTRL_MDP_TRIGGER__SHIFT) & DSI_TRIG_CTRL_MDP_TRIGGER__MASK;
 }
-#define DSI_TRIG_CTRL_STREAM                                   0x00000100
+#define DSI_TRIG_CTRL_STREAM__MASK                             0x00000300
+#define DSI_TRIG_CTRL_STREAM__SHIFT                            8
+static inline uint32_t DSI_TRIG_CTRL_STREAM(uint32_t val)
+{
+       return ((val) << DSI_TRIG_CTRL_STREAM__SHIFT) & DSI_TRIG_CTRL_STREAM__MASK;
+}
+#define DSI_TRIG_CTRL_BLOCK_DMA_WITHIN_FRAME                   0x00001000
 #define DSI_TRIG_CTRL_TE                                       0x80000000
 
 #define REG_DSI_TRIG_DMA                                       0x0000008c
@@ -274,6 +395,12 @@ static inline uint32_t DSI_CLKOUT_TIMING_CTRL_T_CLK_POST(uint32_t val)
 #define DSI_EOT_PACKET_CTRL_RX_EOT_IGNORE                      0x00000010
 
 #define REG_DSI_LANE_SWAP_CTRL                                 0x000000ac
+#define DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL__MASK                  0x00000007
+#define DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL__SHIFT                 0
+static inline uint32_t DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL(enum dsi_lane_swap val)
+{
+       return ((val) << DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL__SHIFT) & DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL__MASK;
+}
 
 #define REG_DSI_ERR_INT_MASK0                                  0x00000108
 
@@ -282,8 +409,36 @@ static inline uint32_t DSI_CLKOUT_TIMING_CTRL_T_CLK_POST(uint32_t val)
 #define REG_DSI_RESET                                          0x00000114
 
 #define REG_DSI_CLK_CTRL                                       0x00000118
+#define DSI_CLK_CTRL_AHBS_HCLK_ON                              0x00000001
+#define DSI_CLK_CTRL_AHBM_SCLK_ON                              0x00000002
+#define DSI_CLK_CTRL_PCLK_ON                                   0x00000004
+#define DSI_CLK_CTRL_DSICLK_ON                                 0x00000008
+#define DSI_CLK_CTRL_BYTECLK_ON                                        0x00000010
+#define DSI_CLK_CTRL_ESCCLK_ON                                 0x00000020
+#define DSI_CLK_CTRL_FORCE_ON_DYN_AHBM_HCLK                    0x00000200
+
+#define REG_DSI_CLK_STATUS                                     0x0000011c
+#define DSI_CLK_STATUS_PLL_UNLOCKED                            0x00010000
 
 #define REG_DSI_PHY_RESET                                      0x00000128
+#define DSI_PHY_RESET_RESET                                    0x00000001
+
+#define REG_DSI_RDBK_DATA_CTRL                                 0x000001d0
+#define DSI_RDBK_DATA_CTRL_COUNT__MASK                         0x00ff0000
+#define DSI_RDBK_DATA_CTRL_COUNT__SHIFT                                16
+static inline uint32_t DSI_RDBK_DATA_CTRL_COUNT(uint32_t val)
+{
+       return ((val) << DSI_RDBK_DATA_CTRL_COUNT__SHIFT) & DSI_RDBK_DATA_CTRL_COUNT__MASK;
+}
+#define DSI_RDBK_DATA_CTRL_CLR                                 0x00000001
+
+#define REG_DSI_VERSION                                                0x000001f0
+#define DSI_VERSION_MAJOR__MASK                                        0xff000000
+#define DSI_VERSION_MAJOR__SHIFT                               24
+static inline uint32_t DSI_VERSION_MAJOR(uint32_t val)
+{
+       return ((val) << DSI_VERSION_MAJOR__SHIFT) & DSI_VERSION_MAJOR__MASK;
+}
 
 #define REG_DSI_PHY_PLL_CTRL_0                                 0x00000200
 #define DSI_PHY_PLL_CTRL_0_ENABLE                              0x00000001
@@ -501,5 +656,184 @@ static inline uint32_t REG_DSI_8960_LN_TEST_STR_1(uint32_t i0) { return 0x000003
 #define REG_DSI_8960_PHY_CAL_STATUS                            0x00000550
 #define DSI_8960_PHY_CAL_STATUS_CAL_BUSY                       0x00000010
 
+static inline uint32_t REG_DSI_28nm_PHY_LN(uint32_t i0) { return 0x00000000 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_CFG_0(uint32_t i0) { return 0x00000000 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_CFG_1(uint32_t i0) { return 0x00000004 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_CFG_2(uint32_t i0) { return 0x00000008 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_CFG_3(uint32_t i0) { return 0x0000000c + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_CFG_4(uint32_t i0) { return 0x00000010 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_TEST_DATAPATH(uint32_t i0) { return 0x00000014 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_DEBUG_SEL(uint32_t i0) { return 0x00000018 + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_TEST_STR_0(uint32_t i0) { return 0x0000001c + 0x40*i0; }
+
+static inline uint32_t REG_DSI_28nm_PHY_LN_TEST_STR_1(uint32_t i0) { return 0x00000020 + 0x40*i0; }
+
+#define REG_DSI_28nm_PHY_LNCK_CFG_0                            0x00000100
+
+#define REG_DSI_28nm_PHY_LNCK_CFG_1                            0x00000104
+
+#define REG_DSI_28nm_PHY_LNCK_CFG_2                            0x00000108
+
+#define REG_DSI_28nm_PHY_LNCK_CFG_3                            0x0000010c
+
+#define REG_DSI_28nm_PHY_LNCK_CFG_4                            0x00000110
+
+#define REG_DSI_28nm_PHY_LNCK_TEST_DATAPATH                    0x00000114
+
+#define REG_DSI_28nm_PHY_LNCK_DEBUG_SEL                                0x00000118
+
+#define REG_DSI_28nm_PHY_LNCK_TEST_STR0                                0x0000011c
+
+#define REG_DSI_28nm_PHY_LNCK_TEST_STR1                                0x00000120
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_0                         0x00000140
+#define DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO__MASK              0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO__SHIFT             0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_1                         0x00000144
+#define DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL__MASK             0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL__SHIFT            0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_2                         0x00000148
+#define DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE__MASK           0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE__SHIFT          0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_3                         0x0000014c
+#define DSI_28nm_PHY_TIMING_CTRL_3_CLK_ZERO_8                  0x00000001
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_4                         0x00000150
+#define DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT__MASK               0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT__SHIFT              0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_5                         0x00000154
+#define DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO__MASK               0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO__SHIFT              0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_6                         0x00000158
+#define DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE__MASK            0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE__SHIFT           0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_7                         0x0000015c
+#define DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL__MASK              0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL__SHIFT             0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_8                         0x00000160
+#define DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST__MASK               0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST__SHIFT              0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_9                         0x00000164
+#define DSI_28nm_PHY_TIMING_CTRL_9_TA_GO__MASK                 0x00000007
+#define DSI_28nm_PHY_TIMING_CTRL_9_TA_GO__SHIFT                        0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_9_TA_GO(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_9_TA_GO__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_9_TA_GO__MASK;
+}
+#define DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE__MASK               0x00000070
+#define DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE__SHIFT              4
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_10                                0x00000168
+#define DSI_28nm_PHY_TIMING_CTRL_10_TA_GET__MASK               0x00000007
+#define DSI_28nm_PHY_TIMING_CTRL_10_TA_GET__SHIFT              0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_10_TA_GET(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_10_TA_GET__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_10_TA_GET__MASK;
+}
+
+#define REG_DSI_28nm_PHY_TIMING_CTRL_11                                0x0000016c
+#define DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD__MASK            0x000000ff
+#define DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD__SHIFT           0
+static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(uint32_t val)
+{
+       return ((val) << DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD__MASK;
+}
+
+#define REG_DSI_28nm_PHY_CTRL_0                                        0x00000170
+
+#define REG_DSI_28nm_PHY_CTRL_1                                        0x00000174
+
+#define REG_DSI_28nm_PHY_CTRL_2                                        0x00000178
+
+#define REG_DSI_28nm_PHY_CTRL_3                                        0x0000017c
+
+#define REG_DSI_28nm_PHY_CTRL_4                                        0x00000180
+
+#define REG_DSI_28nm_PHY_STRENGTH_0                            0x00000184
+
+#define REG_DSI_28nm_PHY_STRENGTH_1                            0x00000188
+
+#define REG_DSI_28nm_PHY_BIST_CTRL_0                           0x000001b4
+
+#define REG_DSI_28nm_PHY_BIST_CTRL_1                           0x000001b8
+
+#define REG_DSI_28nm_PHY_BIST_CTRL_2                           0x000001bc
+
+#define REG_DSI_28nm_PHY_BIST_CTRL_3                           0x000001c0
+
+#define REG_DSI_28nm_PHY_BIST_CTRL_4                           0x000001c4
+
+#define REG_DSI_28nm_PHY_BIST_CTRL_5                           0x000001c8
+
+#define REG_DSI_28nm_PHY_GLBL_TEST_CTRL                                0x000001d4
+
+#define REG_DSI_28nm_PHY_LDO_CNTRL                             0x000001dc
+
+#define REG_DSI_28nm_PHY_REGULATOR_CTRL_0                      0x00000000
+
+#define REG_DSI_28nm_PHY_REGULATOR_CTRL_1                      0x00000004
+
+#define REG_DSI_28nm_PHY_REGULATOR_CTRL_2                      0x00000008
+
+#define REG_DSI_28nm_PHY_REGULATOR_CTRL_3                      0x0000000c
+
+#define REG_DSI_28nm_PHY_REGULATOR_CTRL_4                      0x00000010
+
+#define REG_DSI_28nm_PHY_REGULATOR_CTRL_5                      0x00000014
+
+#define REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG                 0x00000018
+
 
 #endif /* DSI_XML */
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
new file mode 100644 (file)
index 0000000..fdc54e3
--- /dev/null
@@ -0,0 +1,1993 @@
+/*
+ * Copyright (c) 2015, 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 <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spinlock.h>
+#include <video/mipi_display.h>
+
+#include "dsi.h"
+#include "dsi.xml.h"
+
+#define MSM_DSI_VER_MAJOR_V2   0x02
+#define MSM_DSI_VER_MAJOR_6G   0x03
+#define MSM_DSI_6G_VER_MINOR_V1_0      0x10000000
+#define MSM_DSI_6G_VER_MINOR_V1_1      0x10010000
+#define MSM_DSI_6G_VER_MINOR_V1_1_1    0x10010001
+#define MSM_DSI_6G_VER_MINOR_V1_2      0x10020000
+#define MSM_DSI_6G_VER_MINOR_V1_3_1    0x10030001
+
+#define DSI_6G_REG_SHIFT       4
+
+#define DSI_REGULATOR_MAX      8
+struct dsi_reg_entry {
+       char name[32];
+       int min_voltage;
+       int max_voltage;
+       int enable_load;
+       int disable_load;
+};
+
+struct dsi_reg_config {
+       int num;
+       struct dsi_reg_entry regs[DSI_REGULATOR_MAX];
+};
+
+struct dsi_config {
+       u32 major;
+       u32 minor;
+       u32 io_offset;
+       enum msm_dsi_phy_type phy_type;
+       struct dsi_reg_config reg_cfg;
+};
+
+static const struct dsi_config dsi_cfgs[] = {
+       {MSM_DSI_VER_MAJOR_V2, 0, 0, MSM_DSI_PHY_UNKNOWN},
+       { /* 8974 v1 */
+               .major = MSM_DSI_VER_MAJOR_6G,
+               .minor = MSM_DSI_6G_VER_MINOR_V1_0,
+               .io_offset = DSI_6G_REG_SHIFT,
+               .phy_type = MSM_DSI_PHY_28NM,
+               .reg_cfg = {
+                       .num = 4,
+                       .regs = {
+                               {"gdsc", -1, -1, -1, -1},
+                               {"vdd", 3000000, 3000000, 150000, 100},
+                               {"vdda", 1200000, 1200000, 100000, 100},
+                               {"vddio", 1800000, 1800000, 100000, 100},
+                       },
+               },
+       },
+       { /* 8974 v2 */
+               .major = MSM_DSI_VER_MAJOR_6G,
+               .minor = MSM_DSI_6G_VER_MINOR_V1_1,
+               .io_offset = DSI_6G_REG_SHIFT,
+               .phy_type = MSM_DSI_PHY_28NM,
+               .reg_cfg = {
+                       .num = 4,
+                       .regs = {
+                               {"gdsc", -1, -1, -1, -1},
+                               {"vdd", 3000000, 3000000, 150000, 100},
+                               {"vdda", 1200000, 1200000, 100000, 100},
+                               {"vddio", 1800000, 1800000, 100000, 100},
+                       },
+               },
+       },
+       { /* 8974 v3 */
+               .major = MSM_DSI_VER_MAJOR_6G,
+               .minor = MSM_DSI_6G_VER_MINOR_V1_1_1,
+               .io_offset = DSI_6G_REG_SHIFT,
+               .phy_type = MSM_DSI_PHY_28NM,
+               .reg_cfg = {
+                       .num = 4,
+                       .regs = {
+                               {"gdsc", -1, -1, -1, -1},
+                               {"vdd", 3000000, 3000000, 150000, 100},
+                               {"vdda", 1200000, 1200000, 100000, 100},
+                               {"vddio", 1800000, 1800000, 100000, 100},
+                       },
+               },
+       },
+       { /* 8084 */
+               .major = MSM_DSI_VER_MAJOR_6G,
+               .minor = MSM_DSI_6G_VER_MINOR_V1_2,
+               .io_offset = DSI_6G_REG_SHIFT,
+               .phy_type = MSM_DSI_PHY_28NM,
+               .reg_cfg = {
+                       .num = 4,
+                       .regs = {
+                               {"gdsc", -1, -1, -1, -1},
+                               {"vdd", 3000000, 3000000, 150000, 100},
+                               {"vdda", 1200000, 1200000, 100000, 100},
+                               {"vddio", 1800000, 1800000, 100000, 100},
+                       },
+               },
+       },
+       { /* 8916 */
+               .major = MSM_DSI_VER_MAJOR_6G,
+               .minor = MSM_DSI_6G_VER_MINOR_V1_3_1,
+               .io_offset = DSI_6G_REG_SHIFT,
+               .phy_type = MSM_DSI_PHY_28NM,
+               .reg_cfg = {
+                       .num = 4,
+                       .regs = {
+                               {"gdsc", -1, -1, -1, -1},
+                               {"vdd", 2850000, 2850000, 100000, 100},
+                               {"vdda", 1200000, 1200000, 100000, 100},
+                               {"vddio", 1800000, 1800000, 100000, 100},
+                       },
+               },
+       },
+};
+
+static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor)
+{
+       u32 ver;
+       u32 ver_6g;
+
+       if (!major || !minor)
+               return -EINVAL;
+
+       /* From DSI6G(v3), addition of a 6G_HW_VERSION register at offset 0
+        * makes all other registers 4-byte shifted down.
+        */
+       ver_6g = msm_readl(base + REG_DSI_6G_HW_VERSION);
+       if (ver_6g == 0) {
+               ver = msm_readl(base + REG_DSI_VERSION);
+               ver = FIELD(ver, DSI_VERSION_MAJOR);
+               if (ver <= MSM_DSI_VER_MAJOR_V2) {
+                       /* old versions */
+                       *major = ver;
+                       *minor = 0;
+                       return 0;
+               } else {
+                       return -EINVAL;
+               }
+       } else {
+               ver = msm_readl(base + DSI_6G_REG_SHIFT + REG_DSI_VERSION);
+               ver = FIELD(ver, DSI_VERSION_MAJOR);
+               if (ver == MSM_DSI_VER_MAJOR_6G) {
+                       /* 6G version */
+                       *major = ver;
+                       *minor = ver_6g;
+                       return 0;
+               } else {
+                       return -EINVAL;
+               }
+       }
+}
+
+#define DSI_ERR_STATE_ACK                      0x0000
+#define DSI_ERR_STATE_TIMEOUT                  0x0001
+#define DSI_ERR_STATE_DLN0_PHY                 0x0002
+#define DSI_ERR_STATE_FIFO                     0x0004
+#define DSI_ERR_STATE_MDP_FIFO_UNDERFLOW       0x0008
+#define DSI_ERR_STATE_INTERLEAVE_OP_CONTENTION 0x0010
+#define DSI_ERR_STATE_PLL_UNLOCKED             0x0020
+
+#define DSI_CLK_CTRL_ENABLE_CLKS       \
+               (DSI_CLK_CTRL_AHBS_HCLK_ON | DSI_CLK_CTRL_AHBM_SCLK_ON | \
+               DSI_CLK_CTRL_PCLK_ON | DSI_CLK_CTRL_DSICLK_ON | \
+               DSI_CLK_CTRL_BYTECLK_ON | DSI_CLK_CTRL_ESCCLK_ON | \
+               DSI_CLK_CTRL_FORCE_ON_DYN_AHBM_HCLK)
+
+struct msm_dsi_host {
+       struct mipi_dsi_host base;
+
+       struct platform_device *pdev;
+       struct drm_device *dev;
+
+       int id;
+
+       void __iomem *ctrl_base;
+       struct regulator_bulk_data supplies[DSI_REGULATOR_MAX];
+       struct clk *mdp_core_clk;
+       struct clk *ahb_clk;
+       struct clk *axi_clk;
+       struct clk *mmss_misc_ahb_clk;
+       struct clk *byte_clk;
+       struct clk *esc_clk;
+       struct clk *pixel_clk;
+       u32 byte_clk_rate;
+
+       struct gpio_desc *disp_en_gpio;
+       struct gpio_desc *te_gpio;
+
+       const struct dsi_config *cfg;
+
+       struct completion dma_comp;
+       struct completion video_comp;
+       struct mutex dev_mutex;
+       struct mutex cmd_mutex;
+       struct mutex clk_mutex;
+       spinlock_t intr_lock; /* Protect interrupt ctrl register */
+
+       u32 err_work_state;
+       struct work_struct err_work;
+       struct workqueue_struct *workqueue;
+
+       struct drm_gem_object *tx_gem_obj;
+       u8 *rx_buf;
+
+       struct drm_display_mode *mode;
+
+       /* Panel info */
+       struct device_node *panel_node;
+       unsigned int channel;
+       unsigned int lanes;
+       enum mipi_dsi_pixel_format format;
+       unsigned long mode_flags;
+
+       u32 dma_cmd_ctrl_restore;
+
+       bool registered;
+       bool power_on;
+       int irq;
+};
+
+static u32 dsi_get_bpp(const enum mipi_dsi_pixel_format fmt)
+{
+       switch (fmt) {
+       case MIPI_DSI_FMT_RGB565:               return 16;
+       case MIPI_DSI_FMT_RGB666_PACKED:        return 18;
+       case MIPI_DSI_FMT_RGB666:
+       case MIPI_DSI_FMT_RGB888:
+       default:                                return 24;
+       }
+}
+
+static inline u32 dsi_read(struct msm_dsi_host *msm_host, u32 reg)
+{
+       return msm_readl(msm_host->ctrl_base + msm_host->cfg->io_offset + reg);
+}
+static inline void dsi_write(struct msm_dsi_host *msm_host, u32 reg, u32 data)
+{
+       msm_writel(data, msm_host->ctrl_base + msm_host->cfg->io_offset + reg);
+}
+
+static int dsi_host_regulator_enable(struct msm_dsi_host *msm_host);
+static void dsi_host_regulator_disable(struct msm_dsi_host *msm_host);
+
+static const struct dsi_config *dsi_get_config(struct msm_dsi_host *msm_host)
+{
+       const struct dsi_config *cfg;
+       struct regulator *gdsc_reg;
+       int i, ret;
+       u32 major = 0, minor = 0;
+
+       gdsc_reg = regulator_get(&msm_host->pdev->dev, "gdsc");
+       if (IS_ERR_OR_NULL(gdsc_reg)) {
+               pr_err("%s: cannot get gdsc\n", __func__);
+               goto fail;
+       }
+       ret = regulator_enable(gdsc_reg);
+       if (ret) {
+               pr_err("%s: unable to enable gdsc\n", __func__);
+               regulator_put(gdsc_reg);
+               goto fail;
+       }
+       ret = clk_prepare_enable(msm_host->ahb_clk);
+       if (ret) {
+               pr_err("%s: unable to enable ahb_clk\n", __func__);
+               regulator_disable(gdsc_reg);
+               regulator_put(gdsc_reg);
+               goto fail;
+       }
+
+       ret = dsi_get_version(msm_host->ctrl_base, &major, &minor);
+
+       clk_disable_unprepare(msm_host->ahb_clk);
+       regulator_disable(gdsc_reg);
+       regulator_put(gdsc_reg);
+       if (ret) {
+               pr_err("%s: Invalid version\n", __func__);
+               goto fail;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(dsi_cfgs); i++) {
+               cfg = dsi_cfgs + i;
+               if ((cfg->major == major) && (cfg->minor == minor))
+                       return cfg;
+       }
+       pr_err("%s: Version %x:%x not support\n", __func__, major, minor);
+
+fail:
+       return NULL;
+}
+
+static inline struct msm_dsi_host *to_msm_dsi_host(struct mipi_dsi_host *host)
+{
+       return container_of(host, struct msm_dsi_host, base);
+}
+
+static void dsi_host_regulator_disable(struct msm_dsi_host *msm_host)
+{
+       struct regulator_bulk_data *s = msm_host->supplies;
+       const struct dsi_reg_entry *regs = msm_host->cfg->reg_cfg.regs;
+       int num = msm_host->cfg->reg_cfg.num;
+       int i;
+
+       DBG("");
+       for (i = num - 1; i >= 0; i--)
+               if (regs[i].disable_load >= 0)
+                       regulator_set_optimum_mode(s[i].consumer,
+                                               regs[i].disable_load);
+
+       regulator_bulk_disable(num, s);
+}
+
+static int dsi_host_regulator_enable(struct msm_dsi_host *msm_host)
+{
+       struct regulator_bulk_data *s = msm_host->supplies;
+       const struct dsi_reg_entry *regs = msm_host->cfg->reg_cfg.regs;
+       int num = msm_host->cfg->reg_cfg.num;
+       int ret, i;
+
+       DBG("");
+       for (i = 0; i < num; i++) {
+               if (regs[i].enable_load >= 0) {
+                       ret = regulator_set_optimum_mode(s[i].consumer,
+                                                       regs[i].enable_load);
+                       if (ret < 0) {
+                               pr_err("regulator %d set op mode failed, %d\n",
+                                       i, ret);
+                               goto fail;
+                       }
+               }
+       }
+
+       ret = regulator_bulk_enable(num, s);
+       if (ret < 0) {
+               pr_err("regulator enable failed, %d\n", ret);
+               goto fail;
+       }
+
+       return 0;
+
+fail:
+       for (i--; i >= 0; i--)
+               regulator_set_optimum_mode(s[i].consumer, regs[i].disable_load);
+       return ret;
+}
+
+static int dsi_regulator_init(struct msm_dsi_host *msm_host)
+{
+       struct regulator_bulk_data *s = msm_host->supplies;
+       const struct dsi_reg_entry *regs = msm_host->cfg->reg_cfg.regs;
+       int num = msm_host->cfg->reg_cfg.num;
+       int i, ret;
+
+       for (i = 0; i < num; i++)
+               s[i].supply = regs[i].name;
+
+       ret = devm_regulator_bulk_get(&msm_host->pdev->dev, num, s);
+       if (ret < 0) {
+               pr_err("%s: failed to init regulator, ret=%d\n",
+                                               __func__, ret);
+               return ret;
+       }
+
+       for (i = 0; i < num; i++) {
+               if ((regs[i].min_voltage >= 0) && (regs[i].max_voltage >= 0)) {
+                       ret = regulator_set_voltage(s[i].consumer,
+                               regs[i].min_voltage, regs[i].max_voltage);
+                       if (ret < 0) {
+                               pr_err("regulator %d set voltage failed, %d\n",
+                                       i, ret);
+                               return ret;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int dsi_clk_init(struct msm_dsi_host *msm_host)
+{
+       struct device *dev = &msm_host->pdev->dev;
+       int ret = 0;
+
+       msm_host->mdp_core_clk = devm_clk_get(dev, "mdp_core_clk");
+       if (IS_ERR(msm_host->mdp_core_clk)) {
+               ret = PTR_ERR(msm_host->mdp_core_clk);
+               pr_err("%s: Unable to get mdp core clk. ret=%d\n",
+                       __func__, ret);
+               goto exit;
+       }
+
+       msm_host->ahb_clk = devm_clk_get(dev, "iface_clk");
+       if (IS_ERR(msm_host->ahb_clk)) {
+               ret = PTR_ERR(msm_host->ahb_clk);
+               pr_err("%s: Unable to get mdss ahb clk. ret=%d\n",
+                       __func__, ret);
+               goto exit;
+       }
+
+       msm_host->axi_clk = devm_clk_get(dev, "bus_clk");
+       if (IS_ERR(msm_host->axi_clk)) {
+               ret = PTR_ERR(msm_host->axi_clk);
+               pr_err("%s: Unable to get axi bus clk. ret=%d\n",
+                       __func__, ret);
+               goto exit;
+       }
+
+       msm_host->mmss_misc_ahb_clk = devm_clk_get(dev, "core_mmss_clk");
+       if (IS_ERR(msm_host->mmss_misc_ahb_clk)) {
+               ret = PTR_ERR(msm_host->mmss_misc_ahb_clk);
+               pr_err("%s: Unable to get mmss misc ahb clk. ret=%d\n",
+                       __func__, ret);
+               goto exit;
+       }
+
+       msm_host->byte_clk = devm_clk_get(dev, "byte_clk");
+       if (IS_ERR(msm_host->byte_clk)) {
+               ret = PTR_ERR(msm_host->byte_clk);
+               pr_err("%s: can't find dsi_byte_clk. ret=%d\n",
+                       __func__, ret);
+               msm_host->byte_clk = NULL;
+               goto exit;
+       }
+
+       msm_host->pixel_clk = devm_clk_get(dev, "pixel_clk");
+       if (IS_ERR(msm_host->pixel_clk)) {
+               ret = PTR_ERR(msm_host->pixel_clk);
+               pr_err("%s: can't find dsi_pixel_clk. ret=%d\n",
+                       __func__, ret);
+               msm_host->pixel_clk = NULL;
+               goto exit;
+       }
+
+       msm_host->esc_clk = devm_clk_get(dev, "core_clk");
+       if (IS_ERR(msm_host->esc_clk)) {
+               ret = PTR_ERR(msm_host->esc_clk);
+               pr_err("%s: can't find dsi_esc_clk. ret=%d\n",
+                       __func__, ret);
+               msm_host->esc_clk = NULL;
+               goto exit;
+       }
+
+exit:
+       return ret;
+}
+
+static int dsi_bus_clk_enable(struct msm_dsi_host *msm_host)
+{
+       int ret;
+
+       DBG("id=%d", msm_host->id);
+
+       ret = clk_prepare_enable(msm_host->mdp_core_clk);
+       if (ret) {
+               pr_err("%s: failed to enable mdp_core_clock, %d\n",
+                                                        __func__, ret);
+               goto core_clk_err;
+       }
+
+       ret = clk_prepare_enable(msm_host->ahb_clk);
+       if (ret) {
+               pr_err("%s: failed to enable ahb clock, %d\n", __func__, ret);
+               goto ahb_clk_err;
+       }
+
+       ret = clk_prepare_enable(msm_host->axi_clk);
+       if (ret) {
+               pr_err("%s: failed to enable ahb clock, %d\n", __func__, ret);
+               goto axi_clk_err;
+       }
+
+       ret = clk_prepare_enable(msm_host->mmss_misc_ahb_clk);
+       if (ret) {
+               pr_err("%s: failed to enable mmss misc ahb clk, %d\n",
+                       __func__, ret);
+               goto misc_ahb_clk_err;
+       }
+
+       return 0;
+
+misc_ahb_clk_err:
+       clk_disable_unprepare(msm_host->axi_clk);
+axi_clk_err:
+       clk_disable_unprepare(msm_host->ahb_clk);
+ahb_clk_err:
+       clk_disable_unprepare(msm_host->mdp_core_clk);
+core_clk_err:
+       return ret;
+}
+
+static void dsi_bus_clk_disable(struct msm_dsi_host *msm_host)
+{
+       DBG("");
+       clk_disable_unprepare(msm_host->mmss_misc_ahb_clk);
+       clk_disable_unprepare(msm_host->axi_clk);
+       clk_disable_unprepare(msm_host->ahb_clk);
+       clk_disable_unprepare(msm_host->mdp_core_clk);
+}
+
+static int dsi_link_clk_enable(struct msm_dsi_host *msm_host)
+{
+       int ret;
+
+       DBG("Set clk rates: pclk=%d, byteclk=%d",
+               msm_host->mode->clock, msm_host->byte_clk_rate);
+
+       ret = clk_set_rate(msm_host->byte_clk, msm_host->byte_clk_rate);
+       if (ret) {
+               pr_err("%s: Failed to set rate byte clk, %d\n", __func__, ret);
+               goto error;
+       }
+
+       ret = clk_set_rate(msm_host->pixel_clk, msm_host->mode->clock * 1000);
+       if (ret) {
+               pr_err("%s: Failed to set rate pixel clk, %d\n", __func__, ret);
+               goto error;
+       }
+
+       ret = clk_prepare_enable(msm_host->esc_clk);
+       if (ret) {
+               pr_err("%s: Failed to enable dsi esc clk\n", __func__);
+               goto error;
+       }
+
+       ret = clk_prepare_enable(msm_host->byte_clk);
+       if (ret) {
+               pr_err("%s: Failed to enable dsi byte clk\n", __func__);
+               goto byte_clk_err;
+       }
+
+       ret = clk_prepare_enable(msm_host->pixel_clk);
+       if (ret) {
+               pr_err("%s: Failed to enable dsi pixel clk\n", __func__);
+               goto pixel_clk_err;
+       }
+
+       return 0;
+
+pixel_clk_err:
+       clk_disable_unprepare(msm_host->byte_clk);
+byte_clk_err:
+       clk_disable_unprepare(msm_host->esc_clk);
+error:
+       return ret;
+}
+
+static void dsi_link_clk_disable(struct msm_dsi_host *msm_host)
+{
+       clk_disable_unprepare(msm_host->esc_clk);
+       clk_disable_unprepare(msm_host->pixel_clk);
+       clk_disable_unprepare(msm_host->byte_clk);
+}
+
+static int dsi_clk_ctrl(struct msm_dsi_host *msm_host, bool enable)
+{
+       int ret = 0;
+
+       mutex_lock(&msm_host->clk_mutex);
+       if (enable) {
+               ret = dsi_bus_clk_enable(msm_host);
+               if (ret) {
+                       pr_err("%s: Can not enable bus clk, %d\n",
+                               __func__, ret);
+                       goto unlock_ret;
+               }
+               ret = dsi_link_clk_enable(msm_host);
+               if (ret) {
+                       pr_err("%s: Can not enable link clk, %d\n",
+                               __func__, ret);
+                       dsi_bus_clk_disable(msm_host);
+                       goto unlock_ret;
+               }
+       } else {
+               dsi_link_clk_disable(msm_host);
+               dsi_bus_clk_disable(msm_host);
+       }
+
+unlock_ret:
+       mutex_unlock(&msm_host->clk_mutex);
+       return ret;
+}
+
+static int dsi_calc_clk_rate(struct msm_dsi_host *msm_host)
+{
+       struct drm_display_mode *mode = msm_host->mode;
+       u8 lanes = msm_host->lanes;
+       u32 bpp = dsi_get_bpp(msm_host->format);
+       u32 pclk_rate;
+
+       if (!mode) {
+               pr_err("%s: mode not set\n", __func__);
+               return -EINVAL;
+       }
+
+       pclk_rate = mode->clock * 1000;
+       if (lanes > 0) {
+               msm_host->byte_clk_rate = (pclk_rate * bpp) / (8 * lanes);
+       } else {
+               pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
+               msm_host->byte_clk_rate = (pclk_rate * bpp) / 8;
+       }
+
+       DBG("pclk=%d, bclk=%d", pclk_rate, msm_host->byte_clk_rate);
+
+       return 0;
+}
+
+static void dsi_phy_sw_reset(struct msm_dsi_host *msm_host)
+{
+       DBG("");
+       dsi_write(msm_host, REG_DSI_PHY_RESET, DSI_PHY_RESET_RESET);
+       /* Make sure fully reset */
+       wmb();
+       udelay(1000);
+       dsi_write(msm_host, REG_DSI_PHY_RESET, 0);
+       udelay(100);
+}
+
+static void dsi_intr_ctrl(struct msm_dsi_host *msm_host, u32 mask, int enable)
+{
+       u32 intr;
+       unsigned long flags;
+
+       spin_lock_irqsave(&msm_host->intr_lock, flags);
+       intr = dsi_read(msm_host, REG_DSI_INTR_CTRL);
+
+       if (enable)
+               intr |= mask;
+       else
+               intr &= ~mask;
+
+       DBG("intr=%x enable=%d", intr, enable);
+
+       dsi_write(msm_host, REG_DSI_INTR_CTRL, intr);
+       spin_unlock_irqrestore(&msm_host->intr_lock, flags);
+}
+
+static inline enum dsi_traffic_mode dsi_get_traffic_mode(const u32 mode_flags)
+{
+       if (mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+               return BURST_MODE;
+       else if (mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+               return NON_BURST_SYNCH_PULSE;
+
+       return NON_BURST_SYNCH_EVENT;
+}
+
+static inline enum dsi_vid_dst_format dsi_get_vid_fmt(
+                               const enum mipi_dsi_pixel_format mipi_fmt)
+{
+       switch (mipi_fmt) {
+       case MIPI_DSI_FMT_RGB888:       return VID_DST_FORMAT_RGB888;
+       case MIPI_DSI_FMT_RGB666:       return VID_DST_FORMAT_RGB666_LOOSE;
+       case MIPI_DSI_FMT_RGB666_PACKED:        return VID_DST_FORMAT_RGB666;
+       case MIPI_DSI_FMT_RGB565:       return VID_DST_FORMAT_RGB565;
+       default:                        return VID_DST_FORMAT_RGB888;
+       }
+}
+
+static inline enum dsi_cmd_dst_format dsi_get_cmd_fmt(
+                               const enum mipi_dsi_pixel_format mipi_fmt)
+{
+       switch (mipi_fmt) {
+       case MIPI_DSI_FMT_RGB888:       return CMD_DST_FORMAT_RGB888;
+       case MIPI_DSI_FMT_RGB666_PACKED:
+       case MIPI_DSI_FMT_RGB666:       return VID_DST_FORMAT_RGB666;
+       case MIPI_DSI_FMT_RGB565:       return CMD_DST_FORMAT_RGB565;
+       default:                        return CMD_DST_FORMAT_RGB888;
+       }
+}
+
+static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable,
+                               u32 clk_pre, u32 clk_post)
+{
+       u32 flags = msm_host->mode_flags;
+       enum mipi_dsi_pixel_format mipi_fmt = msm_host->format;
+       u32 data = 0;
+
+       if (!enable) {
+               dsi_write(msm_host, REG_DSI_CTRL, 0);
+               return;
+       }
+
+       if (flags & MIPI_DSI_MODE_VIDEO) {
+               if (flags & MIPI_DSI_MODE_VIDEO_HSE)
+                       data |= DSI_VID_CFG0_PULSE_MODE_HSA_HE;
+               if (flags & MIPI_DSI_MODE_VIDEO_HFP)
+                       data |= DSI_VID_CFG0_HFP_POWER_STOP;
+               if (flags & MIPI_DSI_MODE_VIDEO_HBP)
+                       data |= DSI_VID_CFG0_HBP_POWER_STOP;
+               if (flags & MIPI_DSI_MODE_VIDEO_HSA)
+                       data |= DSI_VID_CFG0_HSA_POWER_STOP;
+               /* Always set low power stop mode for BLLP
+                * to let command engine send packets
+                */
+               data |= DSI_VID_CFG0_EOF_BLLP_POWER_STOP |
+                       DSI_VID_CFG0_BLLP_POWER_STOP;
+               data |= DSI_VID_CFG0_TRAFFIC_MODE(dsi_get_traffic_mode(flags));
+               data |= DSI_VID_CFG0_DST_FORMAT(dsi_get_vid_fmt(mipi_fmt));
+               data |= DSI_VID_CFG0_VIRT_CHANNEL(msm_host->channel);
+               dsi_write(msm_host, REG_DSI_VID_CFG0, data);
+
+               /* Do not swap RGB colors */
+               data = DSI_VID_CFG1_RGB_SWAP(SWAP_RGB);
+               dsi_write(msm_host, REG_DSI_VID_CFG1, 0);
+       } else {
+               /* Do not swap RGB colors */
+               data = DSI_CMD_CFG0_RGB_SWAP(SWAP_RGB);
+               data |= DSI_CMD_CFG0_DST_FORMAT(dsi_get_cmd_fmt(mipi_fmt));
+               dsi_write(msm_host, REG_DSI_CMD_CFG0, data);
+
+               data = DSI_CMD_CFG1_WR_MEM_START(MIPI_DCS_WRITE_MEMORY_START) |
+                       DSI_CMD_CFG1_WR_MEM_CONTINUE(
+                                       MIPI_DCS_WRITE_MEMORY_CONTINUE);
+               /* Always insert DCS command */
+               data |= DSI_CMD_CFG1_INSERT_DCS_COMMAND;
+               dsi_write(msm_host, REG_DSI_CMD_CFG1, data);
+       }
+
+       dsi_write(msm_host, REG_DSI_CMD_DMA_CTRL,
+                       DSI_CMD_DMA_CTRL_FROM_FRAME_BUFFER |
+                       DSI_CMD_DMA_CTRL_LOW_POWER);
+
+       data = 0;
+       /* Always assume dedicated TE pin */
+       data |= DSI_TRIG_CTRL_TE;
+       data |= DSI_TRIG_CTRL_MDP_TRIGGER(TRIGGER_NONE);
+       data |= DSI_TRIG_CTRL_DMA_TRIGGER(TRIGGER_SW);
+       data |= DSI_TRIG_CTRL_STREAM(msm_host->channel);
+       if ((msm_host->cfg->major == MSM_DSI_VER_MAJOR_6G) &&
+               (msm_host->cfg->minor >= MSM_DSI_6G_VER_MINOR_V1_2))
+               data |= DSI_TRIG_CTRL_BLOCK_DMA_WITHIN_FRAME;
+       dsi_write(msm_host, REG_DSI_TRIG_CTRL, data);
+
+       data = DSI_CLKOUT_TIMING_CTRL_T_CLK_POST(clk_post) |
+               DSI_CLKOUT_TIMING_CTRL_T_CLK_PRE(clk_pre);
+       dsi_write(msm_host, REG_DSI_CLKOUT_TIMING_CTRL, data);
+
+       data = 0;
+       if (!(flags & MIPI_DSI_MODE_EOT_PACKET))
+               data |= DSI_EOT_PACKET_CTRL_TX_EOT_APPEND;
+       dsi_write(msm_host, REG_DSI_EOT_PACKET_CTRL, data);
+
+       /* allow only ack-err-status to generate interrupt */
+       dsi_write(msm_host, REG_DSI_ERR_INT_MASK0, 0x13ff3fe0);
+
+       dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_ERROR, 1);
+
+       dsi_write(msm_host, REG_DSI_CLK_CTRL, DSI_CLK_CTRL_ENABLE_CLKS);
+
+       data = DSI_CTRL_CLK_EN;
+
+       DBG("lane number=%d", msm_host->lanes);
+       if (msm_host->lanes == 2) {
+               data |= DSI_CTRL_LANE1 | DSI_CTRL_LANE2;
+               /* swap lanes for 2-lane panel for better performance */
+               dsi_write(msm_host, REG_DSI_LANE_SWAP_CTRL,
+                       DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL(LANE_SWAP_1230));
+       } else {
+               /* Take 4 lanes as default */
+               data |= DSI_CTRL_LANE0 | DSI_CTRL_LANE1 | DSI_CTRL_LANE2 |
+                       DSI_CTRL_LANE3;
+               /* Do not swap lanes for 4-lane panel */
+               dsi_write(msm_host, REG_DSI_LANE_SWAP_CTRL,
+                       DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL(LANE_SWAP_0123));
+       }
+       data |= DSI_CTRL_ENABLE;
+
+       dsi_write(msm_host, REG_DSI_CTRL, data);
+}
+
+static void dsi_timing_setup(struct msm_dsi_host *msm_host)
+{
+       struct drm_display_mode *mode = msm_host->mode;
+       u32 hs_start = 0, vs_start = 0; /* take sync start as 0 */
+       u32 h_total = mode->htotal;
+       u32 v_total = mode->vtotal;
+       u32 hs_end = mode->hsync_end - mode->hsync_start;
+       u32 vs_end = mode->vsync_end - mode->vsync_start;
+       u32 ha_start = h_total - mode->hsync_start;
+       u32 ha_end = ha_start + mode->hdisplay;
+       u32 va_start = v_total - mode->vsync_start;
+       u32 va_end = va_start + mode->vdisplay;
+       u32 wc;
+
+       DBG("");
+
+       if (msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) {
+               dsi_write(msm_host, REG_DSI_ACTIVE_H,
+                       DSI_ACTIVE_H_START(ha_start) |
+                       DSI_ACTIVE_H_END(ha_end));
+               dsi_write(msm_host, REG_DSI_ACTIVE_V,
+                       DSI_ACTIVE_V_START(va_start) |
+                       DSI_ACTIVE_V_END(va_end));
+               dsi_write(msm_host, REG_DSI_TOTAL,
+                       DSI_TOTAL_H_TOTAL(h_total - 1) |
+                       DSI_TOTAL_V_TOTAL(v_total - 1));
+
+               dsi_write(msm_host, REG_DSI_ACTIVE_HSYNC,
+                       DSI_ACTIVE_HSYNC_START(hs_start) |
+                       DSI_ACTIVE_HSYNC_END(hs_end));
+               dsi_write(msm_host, REG_DSI_ACTIVE_VSYNC_HPOS, 0);
+               dsi_write(msm_host, REG_DSI_ACTIVE_VSYNC_VPOS,
+                       DSI_ACTIVE_VSYNC_VPOS_START(vs_start) |
+                       DSI_ACTIVE_VSYNC_VPOS_END(vs_end));
+       } else {                /* command mode */
+               /* image data and 1 byte write_memory_start cmd */
+               wc = mode->hdisplay * dsi_get_bpp(msm_host->format) / 8 + 1;
+
+               dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM_CTRL,
+                       DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT(wc) |
+                       DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL(
+                                       msm_host->channel) |
+                       DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE(
+                                       MIPI_DSI_DCS_LONG_WRITE));
+
+               dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM_TOTAL,
+                       DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL(mode->hdisplay) |
+                       DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL(mode->vdisplay));
+       }
+}
+
+static void dsi_sw_reset(struct msm_dsi_host *msm_host)
+{
+       dsi_write(msm_host, REG_DSI_CLK_CTRL, DSI_CLK_CTRL_ENABLE_CLKS);
+       wmb(); /* clocks need to be enabled before reset */
+
+       dsi_write(msm_host, REG_DSI_RESET, 1);
+       wmb(); /* make sure reset happen */
+       dsi_write(msm_host, REG_DSI_RESET, 0);
+}
+
+static void dsi_op_mode_config(struct msm_dsi_host *msm_host,
+                                       bool video_mode, bool enable)
+{
+       u32 dsi_ctrl;
+
+       dsi_ctrl = dsi_read(msm_host, REG_DSI_CTRL);
+
+       if (!enable) {
+               dsi_ctrl &= ~(DSI_CTRL_ENABLE | DSI_CTRL_VID_MODE_EN |
+                               DSI_CTRL_CMD_MODE_EN);
+               dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_CMD_MDP_DONE |
+                                       DSI_IRQ_MASK_VIDEO_DONE, 0);
+       } else {
+               if (video_mode) {
+                       dsi_ctrl |= DSI_CTRL_VID_MODE_EN;
+               } else {                /* command mode */
+                       dsi_ctrl |= DSI_CTRL_CMD_MODE_EN;
+                       dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_CMD_MDP_DONE, 1);
+               }
+               dsi_ctrl |= DSI_CTRL_ENABLE;
+       }
+
+       dsi_write(msm_host, REG_DSI_CTRL, dsi_ctrl);
+}
+
+static void dsi_set_tx_power_mode(int mode, struct msm_dsi_host *msm_host)
+{
+       u32 data;
+
+       data = dsi_read(msm_host, REG_DSI_CMD_DMA_CTRL);
+
+       if (mode == 0)
+               data &= ~DSI_CMD_DMA_CTRL_LOW_POWER;
+       else
+               data |= DSI_CMD_DMA_CTRL_LOW_POWER;
+
+       dsi_write(msm_host, REG_DSI_CMD_DMA_CTRL, data);
+}
+
+static void dsi_wait4video_done(struct msm_dsi_host *msm_host)
+{
+       dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_VIDEO_DONE, 1);
+
+       reinit_completion(&msm_host->video_comp);
+
+       wait_for_completion_timeout(&msm_host->video_comp,
+                       msecs_to_jiffies(70));
+
+       dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_VIDEO_DONE, 0);
+}
+
+static void dsi_wait4video_eng_busy(struct msm_dsi_host *msm_host)
+{
+       if (!(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO))
+               return;
+
+       if (msm_host->power_on) {
+               dsi_wait4video_done(msm_host);
+               /* delay 4 ms to skip BLLP */
+               usleep_range(2000, 4000);
+       }
+}
+
+/* dsi_cmd */
+static int dsi_tx_buf_alloc(struct msm_dsi_host *msm_host, int size)
+{
+       struct drm_device *dev = msm_host->dev;
+       int ret;
+       u32 iova;
+
+       mutex_lock(&dev->struct_mutex);
+       msm_host->tx_gem_obj = msm_gem_new(dev, size, MSM_BO_UNCACHED);
+       if (IS_ERR(msm_host->tx_gem_obj)) {
+               ret = PTR_ERR(msm_host->tx_gem_obj);
+               pr_err("%s: failed to allocate gem, %d\n", __func__, ret);
+               msm_host->tx_gem_obj = NULL;
+               mutex_unlock(&dev->struct_mutex);
+               return ret;
+       }
+
+       ret = msm_gem_get_iova_locked(msm_host->tx_gem_obj, 0, &iova);
+       if (ret) {
+               pr_err("%s: failed to get iova, %d\n", __func__, ret);
+               return ret;
+       }
+       mutex_unlock(&dev->struct_mutex);
+
+       if (iova & 0x07) {
+               pr_err("%s: buf NOT 8 bytes aligned\n", __func__);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void dsi_tx_buf_free(struct msm_dsi_host *msm_host)
+{
+       struct drm_device *dev = msm_host->dev;
+
+       if (msm_host->tx_gem_obj) {
+               msm_gem_put_iova(msm_host->tx_gem_obj, 0);
+               mutex_lock(&dev->struct_mutex);
+               msm_gem_free_object(msm_host->tx_gem_obj);
+               msm_host->tx_gem_obj = NULL;
+               mutex_unlock(&dev->struct_mutex);
+       }
+}
+
+/*
+ * prepare cmd buffer to be txed
+ */
+static int dsi_cmd_dma_add(struct drm_gem_object *tx_gem,
+                       const struct mipi_dsi_msg *msg)
+{
+       struct mipi_dsi_packet packet;
+       int len;
+       int ret;
+       u8 *data;
+
+       ret = mipi_dsi_create_packet(&packet, msg);
+       if (ret) {
+               pr_err("%s: create packet failed, %d\n", __func__, ret);
+               return ret;
+       }
+       len = (packet.size + 3) & (~0x3);
+
+       if (len > tx_gem->size) {
+               pr_err("%s: packet size is too big\n", __func__);
+               return -EINVAL;
+       }
+
+       data = msm_gem_vaddr(tx_gem);
+
+       if (IS_ERR(data)) {
+               ret = PTR_ERR(data);
+               pr_err("%s: get vaddr failed, %d\n", __func__, ret);
+               return ret;
+       }
+
+       /* MSM specific command format in memory */
+       data[0] = packet.header[1];
+       data[1] = packet.header[2];
+       data[2] = packet.header[0];
+       data[3] = BIT(7); /* Last packet */
+       if (mipi_dsi_packet_format_is_long(msg->type))
+               data[3] |= BIT(6);
+       if (msg->rx_buf && msg->rx_len)
+               data[3] |= BIT(5);
+
+       /* Long packet */
+       if (packet.payload && packet.payload_length)
+               memcpy(data + 4, packet.payload, packet.payload_length);
+
+       /* Append 0xff to the end */
+       if (packet.size < len)
+               memset(data + packet.size, 0xff, len - packet.size);
+
+       return len;
+}
+
+/*
+ * dsi_short_read1_resp: 1 parameter
+ */
+static int dsi_short_read1_resp(u8 *buf, const struct mipi_dsi_msg *msg)
+{
+       u8 *data = msg->rx_buf;
+       if (data && (msg->rx_len >= 1)) {
+               *data = buf[1]; /* strip out dcs type */
+               return 1;
+       } else {
+               pr_err("%s: read data does not match with rx_buf len %d\n",
+                       __func__, msg->rx_len);
+               return -EINVAL;
+       }
+}
+
+/*
+ * dsi_short_read2_resp: 2 parameter
+ */
+static int dsi_short_read2_resp(u8 *buf, const struct mipi_dsi_msg *msg)
+{
+       u8 *data = msg->rx_buf;
+       if (data && (msg->rx_len >= 2)) {
+               data[0] = buf[1]; /* strip out dcs type */
+               data[1] = buf[2];
+               return 2;
+       } else {
+               pr_err("%s: read data does not match with rx_buf len %d\n",
+                       __func__, msg->rx_len);
+               return -EINVAL;
+       }
+}
+
+static int dsi_long_read_resp(u8 *buf, const struct mipi_dsi_msg *msg)
+{
+       /* strip out 4 byte dcs header */
+       if (msg->rx_buf && msg->rx_len)
+               memcpy(msg->rx_buf, buf + 4, msg->rx_len);
+
+       return msg->rx_len;
+}
+
+
+static int dsi_cmd_dma_tx(struct msm_dsi_host *msm_host, int len)
+{
+       int ret;
+       u32 iova;
+       bool triggered;
+
+       ret = msm_gem_get_iova(msm_host->tx_gem_obj, 0, &iova);
+       if (ret) {
+               pr_err("%s: failed to get iova: %d\n", __func__, ret);
+               return ret;
+       }
+
+       reinit_completion(&msm_host->dma_comp);
+
+       dsi_wait4video_eng_busy(msm_host);
+
+       triggered = msm_dsi_manager_cmd_xfer_trigger(
+                                               msm_host->id, iova, len);
+       if (triggered) {
+               ret = wait_for_completion_timeout(&msm_host->dma_comp,
+                                       msecs_to_jiffies(200));
+               DBG("ret=%d", ret);
+               if (ret == 0)
+                       ret = -ETIMEDOUT;
+               else
+                       ret = len;
+       } else
+               ret = len;
+
+       return ret;
+}
+
+static int dsi_cmd_dma_rx(struct msm_dsi_host *msm_host,
+                       u8 *buf, int rx_byte, int pkt_size)
+{
+       u32 *lp, *temp, data;
+       int i, j = 0, cnt;
+       bool ack_error = false;
+       u32 read_cnt;
+       u8 reg[16];
+       int repeated_bytes = 0;
+       int buf_offset = buf - msm_host->rx_buf;
+
+       lp = (u32 *)buf;
+       temp = (u32 *)reg;
+       cnt = (rx_byte + 3) >> 2;
+       if (cnt > 4)
+               cnt = 4; /* 4 x 32 bits registers only */
+
+       /* Calculate real read data count */
+       read_cnt = dsi_read(msm_host, 0x1d4) >> 16;
+
+       ack_error = (rx_byte == 4) ?
+               (read_cnt == 8) : /* short pkt + 4-byte error pkt */
+               (read_cnt == (pkt_size + 6 + 4)); /* long pkt+4-byte error pkt*/
+
+       if (ack_error)
+               read_cnt -= 4; /* Remove 4 byte error pkt */
+
+       /*
+        * In case of multiple reads from the panel, after the first read, there
+        * is possibility that there are some bytes in the payload repeating in
+        * the RDBK_DATA registers. Since we read all the parameters from the
+        * panel right from the first byte for every pass. We need to skip the
+        * repeating bytes and then append the new parameters to the rx buffer.
+        */
+       if (read_cnt > 16) {
+               int bytes_shifted;
+               /* Any data more than 16 bytes will be shifted out.
+                * The temp read buffer should already contain these bytes.
+                * The remaining bytes in read buffer are the repeated bytes.
+                */
+               bytes_shifted = read_cnt - 16;
+               repeated_bytes = buf_offset - bytes_shifted;
+       }
+
+       for (i = cnt - 1; i >= 0; i--) {
+               data = dsi_read(msm_host, REG_DSI_RDBK_DATA(i));
+               *temp++ = ntohl(data); /* to host byte order */
+               DBG("data = 0x%x and ntohl(data) = 0x%x", data, ntohl(data));
+       }
+
+       for (i = repeated_bytes; i < 16; i++)
+               buf[j++] = reg[i];
+
+       return j;
+}
+
+static int dsi_cmds2buf_tx(struct msm_dsi_host *msm_host,
+                               const struct mipi_dsi_msg *msg)
+{
+       int len, ret;
+       int bllp_len = msm_host->mode->hdisplay *
+                       dsi_get_bpp(msm_host->format) / 8;
+
+       len = dsi_cmd_dma_add(msm_host->tx_gem_obj, msg);
+       if (!len) {
+               pr_err("%s: failed to add cmd type = 0x%x\n",
+                       __func__,  msg->type);
+               return -EINVAL;
+       }
+
+       /* for video mode, do not send cmds more than
+       * one pixel line, since it only transmit it
+       * during BLLP.
+       */
+       /* TODO: if the command is sent in LP mode, the bit rate is only
+        * half of esc clk rate. In this case, if the video is already
+        * actively streaming, we need to check more carefully if the
+        * command can be fit into one BLLP.
+        */
+       if ((msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) && (len > bllp_len)) {
+               pr_err("%s: cmd cannot fit into BLLP period, len=%d\n",
+                       __func__, len);
+               return -EINVAL;
+       }
+
+       ret = dsi_cmd_dma_tx(msm_host, len);
+       if (ret < len) {
+               pr_err("%s: cmd dma tx failed, type=0x%x, data0=0x%x, len=%d\n",
+                       __func__, msg->type, (*(u8 *)(msg->tx_buf)), len);
+               return -ECOMM;
+       }
+
+       return len;
+}
+
+static void dsi_sw_reset_restore(struct msm_dsi_host *msm_host)
+{
+       u32 data0, data1;
+
+       data0 = dsi_read(msm_host, REG_DSI_CTRL);
+       data1 = data0;
+       data1 &= ~DSI_CTRL_ENABLE;
+       dsi_write(msm_host, REG_DSI_CTRL, data1);
+       /*
+        * dsi controller need to be disabled before
+        * clocks turned on
+        */
+       wmb();
+
+       dsi_write(msm_host, REG_DSI_CLK_CTRL, DSI_CLK_CTRL_ENABLE_CLKS);
+       wmb();  /* make sure clocks enabled */
+
+       /* dsi controller can only be reset while clocks are running */
+       dsi_write(msm_host, REG_DSI_RESET, 1);
+       wmb();  /* make sure reset happen */
+       dsi_write(msm_host, REG_DSI_RESET, 0);
+       wmb();  /* controller out of reset */
+       dsi_write(msm_host, REG_DSI_CTRL, data0);
+       wmb();  /* make sure dsi controller enabled again */
+}
+
+static void dsi_err_worker(struct work_struct *work)
+{
+       struct msm_dsi_host *msm_host =
+               container_of(work, struct msm_dsi_host, err_work);
+       u32 status = msm_host->err_work_state;
+
+       pr_err("%s: status=%x\n", __func__, status);
+       if (status & DSI_ERR_STATE_MDP_FIFO_UNDERFLOW)
+               dsi_sw_reset_restore(msm_host);
+
+       /* It is safe to clear here because error irq is disabled. */
+       msm_host->err_work_state = 0;
+
+       /* enable dsi error interrupt */
+       dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_ERROR, 1);
+}
+
+static void dsi_ack_err_status(struct msm_dsi_host *msm_host)
+{
+       u32 status;
+
+       status = dsi_read(msm_host, REG_DSI_ACK_ERR_STATUS);
+
+       if (status) {
+               dsi_write(msm_host, REG_DSI_ACK_ERR_STATUS, status);
+               /* Writing of an extra 0 needed to clear error bits */
+               dsi_write(msm_host, REG_DSI_ACK_ERR_STATUS, 0);
+               msm_host->err_work_state |= DSI_ERR_STATE_ACK;
+       }
+}
+
+static void dsi_timeout_status(struct msm_dsi_host *msm_host)
+{
+       u32 status;
+
+       status = dsi_read(msm_host, REG_DSI_TIMEOUT_STATUS);
+
+       if (status) {
+               dsi_write(msm_host, REG_DSI_TIMEOUT_STATUS, status);
+               msm_host->err_work_state |= DSI_ERR_STATE_TIMEOUT;
+       }
+}
+
+static void dsi_dln0_phy_err(struct msm_dsi_host *msm_host)
+{
+       u32 status;
+
+       status = dsi_read(msm_host, REG_DSI_DLN0_PHY_ERR);
+
+       if (status) {
+               dsi_write(msm_host, REG_DSI_DLN0_PHY_ERR, status);
+               msm_host->err_work_state |= DSI_ERR_STATE_DLN0_PHY;
+       }
+}
+
+static void dsi_fifo_status(struct msm_dsi_host *msm_host)
+{
+       u32 status;
+
+       status = dsi_read(msm_host, REG_DSI_FIFO_STATUS);
+
+       /* fifo underflow, overflow */
+       if (status) {
+               dsi_write(msm_host, REG_DSI_FIFO_STATUS, status);
+               msm_host->err_work_state |= DSI_ERR_STATE_FIFO;
+               if (status & DSI_FIFO_STATUS_CMD_MDP_FIFO_UNDERFLOW)
+                       msm_host->err_work_state |=
+                                       DSI_ERR_STATE_MDP_FIFO_UNDERFLOW;
+       }
+}
+
+static void dsi_status(struct msm_dsi_host *msm_host)
+{
+       u32 status;
+
+       status = dsi_read(msm_host, REG_DSI_STATUS0);
+
+       if (status & DSI_STATUS0_INTERLEAVE_OP_CONTENTION) {
+               dsi_write(msm_host, REG_DSI_STATUS0, status);
+               msm_host->err_work_state |=
+                       DSI_ERR_STATE_INTERLEAVE_OP_CONTENTION;
+       }
+}
+
+static void dsi_clk_status(struct msm_dsi_host *msm_host)
+{
+       u32 status;
+
+       status = dsi_read(msm_host, REG_DSI_CLK_STATUS);
+
+       if (status & DSI_CLK_STATUS_PLL_UNLOCKED) {
+               dsi_write(msm_host, REG_DSI_CLK_STATUS, status);
+               msm_host->err_work_state |= DSI_ERR_STATE_PLL_UNLOCKED;
+       }
+}
+
+static void dsi_error(struct msm_dsi_host *msm_host)
+{
+       /* disable dsi error interrupt */
+       dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_ERROR, 0);
+
+       dsi_clk_status(msm_host);
+       dsi_fifo_status(msm_host);
+       dsi_ack_err_status(msm_host);
+       dsi_timeout_status(msm_host);
+       dsi_status(msm_host);
+       dsi_dln0_phy_err(msm_host);
+
+       queue_work(msm_host->workqueue, &msm_host->err_work);
+}
+
+static irqreturn_t dsi_host_irq(int irq, void *ptr)
+{
+       struct msm_dsi_host *msm_host = ptr;
+       u32 isr;
+       unsigned long flags;
+
+       if (!msm_host->ctrl_base)
+               return IRQ_HANDLED;
+
+       spin_lock_irqsave(&msm_host->intr_lock, flags);
+       isr = dsi_read(msm_host, REG_DSI_INTR_CTRL);
+       dsi_write(msm_host, REG_DSI_INTR_CTRL, isr);
+       spin_unlock_irqrestore(&msm_host->intr_lock, flags);
+
+       DBG("isr=0x%x, id=%d", isr, msm_host->id);
+
+       if (isr & DSI_IRQ_ERROR)
+               dsi_error(msm_host);
+
+       if (isr & DSI_IRQ_VIDEO_DONE)
+               complete(&msm_host->video_comp);
+
+       if (isr & DSI_IRQ_CMD_DMA_DONE)
+               complete(&msm_host->dma_comp);
+
+       return IRQ_HANDLED;
+}
+
+static int dsi_host_init_panel_gpios(struct msm_dsi_host *msm_host,
+                       struct device *panel_device)
+{
+       int ret;
+
+       msm_host->disp_en_gpio = devm_gpiod_get(panel_device,
+                                               "disp-enable");
+       if (IS_ERR(msm_host->disp_en_gpio)) {
+               DBG("cannot get disp-enable-gpios %ld",
+                               PTR_ERR(msm_host->disp_en_gpio));
+               msm_host->disp_en_gpio = NULL;
+       }
+       if (msm_host->disp_en_gpio) {
+               ret = gpiod_direction_output(msm_host->disp_en_gpio, 0);
+               if (ret) {
+                       pr_err("cannot set dir to disp-en-gpios %d\n", ret);
+                       return ret;
+               }
+       }
+
+       msm_host->te_gpio = devm_gpiod_get(panel_device, "disp-te");
+       if (IS_ERR(msm_host->te_gpio)) {
+               DBG("cannot get disp-te-gpios %ld", PTR_ERR(msm_host->te_gpio));
+               msm_host->te_gpio = NULL;
+       }
+
+       if (msm_host->te_gpio) {
+               ret = gpiod_direction_input(msm_host->te_gpio);
+               if (ret) {
+                       pr_err("%s: cannot set dir to disp-te-gpios, %d\n",
+                               __func__, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int dsi_host_attach(struct mipi_dsi_host *host,
+                                       struct mipi_dsi_device *dsi)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+       int ret;
+
+       msm_host->channel = dsi->channel;
+       msm_host->lanes = dsi->lanes;
+       msm_host->format = dsi->format;
+       msm_host->mode_flags = dsi->mode_flags;
+
+       msm_host->panel_node = dsi->dev.of_node;
+
+       /* Some gpios defined in panel DT need to be controlled by host */
+       ret = dsi_host_init_panel_gpios(msm_host, &dsi->dev);
+       if (ret)
+               return ret;
+
+       DBG("id=%d", msm_host->id);
+       if (msm_host->dev)
+               drm_helper_hpd_irq_event(msm_host->dev);
+
+       return 0;
+}
+
+static int dsi_host_detach(struct mipi_dsi_host *host,
+                                       struct mipi_dsi_device *dsi)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       msm_host->panel_node = NULL;
+
+       DBG("id=%d", msm_host->id);
+       if (msm_host->dev)
+               drm_helper_hpd_irq_event(msm_host->dev);
+
+       return 0;
+}
+
+static ssize_t dsi_host_transfer(struct mipi_dsi_host *host,
+                                       const struct mipi_dsi_msg *msg)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+       int ret;
+
+       if (!msg || !msm_host->power_on)
+               return -EINVAL;
+
+       mutex_lock(&msm_host->cmd_mutex);
+       ret = msm_dsi_manager_cmd_xfer(msm_host->id, msg);
+       mutex_unlock(&msm_host->cmd_mutex);
+
+       return ret;
+}
+
+static struct mipi_dsi_host_ops dsi_host_ops = {
+       .attach = dsi_host_attach,
+       .detach = dsi_host_detach,
+       .transfer = dsi_host_transfer,
+};
+
+int msm_dsi_host_init(struct msm_dsi *msm_dsi)
+{
+       struct msm_dsi_host *msm_host = NULL;
+       struct platform_device *pdev = msm_dsi->pdev;
+       int ret;
+
+       msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL);
+       if (!msm_host) {
+               pr_err("%s: FAILED: cannot alloc dsi host\n",
+                      __func__);
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       ret = of_property_read_u32(pdev->dev.of_node,
+                               "qcom,dsi-host-index", &msm_host->id);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "%s: host index not specified, ret=%d\n",
+                       __func__, ret);
+               goto fail;
+       }
+       msm_host->pdev = pdev;
+
+       ret = dsi_clk_init(msm_host);
+       if (ret) {
+               pr_err("%s: unable to initialize dsi clks\n", __func__);
+               goto fail;
+       }
+
+       msm_host->ctrl_base = msm_ioremap(pdev, "dsi_ctrl", "DSI CTRL");
+       if (IS_ERR(msm_host->ctrl_base)) {
+               pr_err("%s: unable to map Dsi ctrl base\n", __func__);
+               ret = PTR_ERR(msm_host->ctrl_base);
+               goto fail;
+       }
+
+       msm_host->cfg = dsi_get_config(msm_host);
+       if (!msm_host->cfg) {
+               ret = -EINVAL;
+               pr_err("%s: get config failed\n", __func__);
+               goto fail;
+       }
+
+       ret = dsi_regulator_init(msm_host);
+       if (ret) {
+               pr_err("%s: regulator init failed\n", __func__);
+               goto fail;
+       }
+
+       msm_host->rx_buf = devm_kzalloc(&pdev->dev, SZ_4K, GFP_KERNEL);
+       if (!msm_host->rx_buf) {
+               pr_err("%s: alloc rx temp buf failed\n", __func__);
+               goto fail;
+       }
+
+       init_completion(&msm_host->dma_comp);
+       init_completion(&msm_host->video_comp);
+       mutex_init(&msm_host->dev_mutex);
+       mutex_init(&msm_host->cmd_mutex);
+       mutex_init(&msm_host->clk_mutex);
+       spin_lock_init(&msm_host->intr_lock);
+
+       /* setup workqueue */
+       msm_host->workqueue = alloc_ordered_workqueue("dsi_drm_work", 0);
+       INIT_WORK(&msm_host->err_work, dsi_err_worker);
+
+       msm_dsi->phy = msm_dsi_phy_init(pdev, msm_host->cfg->phy_type,
+                                       msm_host->id);
+       if (!msm_dsi->phy) {
+               ret = -EINVAL;
+               pr_err("%s: phy init failed\n", __func__);
+               goto fail;
+       }
+       msm_dsi->host = &msm_host->base;
+       msm_dsi->id = msm_host->id;
+
+       DBG("Dsi Host %d initialized", msm_host->id);
+       return 0;
+
+fail:
+       return ret;
+}
+
+void msm_dsi_host_destroy(struct mipi_dsi_host *host)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       DBG("");
+       dsi_tx_buf_free(msm_host);
+       if (msm_host->workqueue) {
+               flush_workqueue(msm_host->workqueue);
+               destroy_workqueue(msm_host->workqueue);
+               msm_host->workqueue = NULL;
+       }
+
+       mutex_destroy(&msm_host->clk_mutex);
+       mutex_destroy(&msm_host->cmd_mutex);
+       mutex_destroy(&msm_host->dev_mutex);
+}
+
+int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
+                                       struct drm_device *dev)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+       struct platform_device *pdev = msm_host->pdev;
+       int ret;
+
+       msm_host->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+       if (msm_host->irq < 0) {
+               ret = msm_host->irq;
+               dev_err(dev->dev, "failed to get irq: %d\n", ret);
+               return ret;
+       }
+
+       ret = devm_request_irq(&pdev->dev, msm_host->irq,
+                       dsi_host_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+                       "dsi_isr", msm_host);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to request IRQ%u: %d\n",
+                               msm_host->irq, ret);
+               return ret;
+       }
+
+       msm_host->dev = dev;
+       ret = dsi_tx_buf_alloc(msm_host, SZ_4K);
+       if (ret) {
+               pr_err("%s: alloc tx gem obj failed, %d\n", __func__, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+       struct device_node *node;
+       int ret;
+
+       /* Register mipi dsi host */
+       if (!msm_host->registered) {
+               host->dev = &msm_host->pdev->dev;
+               host->ops = &dsi_host_ops;
+               ret = mipi_dsi_host_register(host);
+               if (ret)
+                       return ret;
+
+               msm_host->registered = true;
+
+               /* If the panel driver has not been probed after host register,
+                * we should defer the host's probe.
+                * It makes sure panel is connected when fbcon detects
+                * connector status and gets the proper display mode to
+                * create framebuffer.
+                */
+               if (check_defer) {
+                       node = of_get_child_by_name(msm_host->pdev->dev.of_node,
+                                                       "panel");
+                       if (node) {
+                               if (!of_drm_find_panel(node))
+                                       return -EPROBE_DEFER;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+void msm_dsi_host_unregister(struct mipi_dsi_host *host)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       if (msm_host->registered) {
+               mipi_dsi_host_unregister(host);
+               host->dev = NULL;
+               host->ops = NULL;
+               msm_host->registered = false;
+       }
+}
+
+int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
+                               const struct mipi_dsi_msg *msg)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       /* TODO: make sure dsi_cmd_mdp is idle.
+        * Since DSI6G v1.2.0, we can set DSI_TRIG_CTRL.BLOCK_DMA_WITHIN_FRAME
+        * to ask H/W to wait until cmd mdp is idle. S/W wait is not needed.
+        * How to handle the old versions? Wait for mdp cmd done?
+        */
+
+       /*
+        * mdss interrupt is generated in mdp core clock domain
+        * mdp clock need to be enabled to receive dsi interrupt
+        */
+       dsi_clk_ctrl(msm_host, 1);
+
+       /* TODO: vote for bus bandwidth */
+
+       if (!(msg->flags & MIPI_DSI_MSG_USE_LPM))
+               dsi_set_tx_power_mode(0, msm_host);
+
+       msm_host->dma_cmd_ctrl_restore = dsi_read(msm_host, REG_DSI_CTRL);
+       dsi_write(msm_host, REG_DSI_CTRL,
+               msm_host->dma_cmd_ctrl_restore |
+               DSI_CTRL_CMD_MODE_EN |
+               DSI_CTRL_ENABLE);
+       dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_CMD_DMA_DONE, 1);
+
+       return 0;
+}
+
+void msm_dsi_host_xfer_restore(struct mipi_dsi_host *host,
+                               const struct mipi_dsi_msg *msg)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_CMD_DMA_DONE, 0);
+       dsi_write(msm_host, REG_DSI_CTRL, msm_host->dma_cmd_ctrl_restore);
+
+       if (!(msg->flags & MIPI_DSI_MSG_USE_LPM))
+               dsi_set_tx_power_mode(1, msm_host);
+
+       /* TODO: unvote for bus bandwidth */
+
+       dsi_clk_ctrl(msm_host, 0);
+}
+
+int msm_dsi_host_cmd_tx(struct mipi_dsi_host *host,
+                               const struct mipi_dsi_msg *msg)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       return dsi_cmds2buf_tx(msm_host, msg);
+}
+
+int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host,
+                               const struct mipi_dsi_msg *msg)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+       int data_byte, rx_byte, dlen, end;
+       int short_response, diff, pkt_size, ret = 0;
+       char cmd;
+       int rlen = msg->rx_len;
+       u8 *buf;
+
+       if (rlen <= 2) {
+               short_response = 1;
+               pkt_size = rlen;
+               rx_byte = 4;
+       } else {
+               short_response = 0;
+               data_byte = 10; /* first read */
+               if (rlen < data_byte)
+                       pkt_size = rlen;
+               else
+                       pkt_size = data_byte;
+               rx_byte = data_byte + 6; /* 4 header + 2 crc */
+       }
+
+       buf = msm_host->rx_buf;
+       end = 0;
+       while (!end) {
+               u8 tx[2] = {pkt_size & 0xff, pkt_size >> 8};
+               struct mipi_dsi_msg max_pkt_size_msg = {
+                       .channel = msg->channel,
+                       .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
+                       .tx_len = 2,
+                       .tx_buf = tx,
+               };
+
+               DBG("rlen=%d pkt_size=%d rx_byte=%d",
+                       rlen, pkt_size, rx_byte);
+
+               ret = dsi_cmds2buf_tx(msm_host, &max_pkt_size_msg);
+               if (ret < 2) {
+                       pr_err("%s: Set max pkt size failed, %d\n",
+                               __func__, ret);
+                       return -EINVAL;
+               }
+
+               if ((msm_host->cfg->major == MSM_DSI_VER_MAJOR_6G) &&
+                       (msm_host->cfg->minor >= MSM_DSI_6G_VER_MINOR_V1_1)) {
+                       /* Clear the RDBK_DATA registers */
+                       dsi_write(msm_host, REG_DSI_RDBK_DATA_CTRL,
+                                       DSI_RDBK_DATA_CTRL_CLR);
+                       wmb(); /* make sure the RDBK registers are cleared */
+                       dsi_write(msm_host, REG_DSI_RDBK_DATA_CTRL, 0);
+                       wmb(); /* release cleared status before transfer */
+               }
+
+               ret = dsi_cmds2buf_tx(msm_host, msg);
+               if (ret < msg->tx_len) {
+                       pr_err("%s: Read cmd Tx failed, %d\n", __func__, ret);
+                       return ret;
+               }
+
+               /*
+                * once cmd_dma_done interrupt received,
+                * return data from client is ready and stored
+                * at RDBK_DATA register already
+                * since rx fifo is 16 bytes, dcs header is kept at first loop,
+                * after that dcs header lost during shift into registers
+                */
+               dlen = dsi_cmd_dma_rx(msm_host, buf, rx_byte, pkt_size);
+
+               if (dlen <= 0)
+                       return 0;
+
+               if (short_response)
+                       break;
+
+               if (rlen <= data_byte) {
+                       diff = data_byte - rlen;
+                       end = 1;
+               } else {
+                       diff = 0;
+                       rlen -= data_byte;
+               }
+
+               if (!end) {
+                       dlen -= 2; /* 2 crc */
+                       dlen -= diff;
+                       buf += dlen;    /* next start position */
+                       data_byte = 14; /* NOT first read */
+                       if (rlen < data_byte)
+                               pkt_size += rlen;
+                       else
+                               pkt_size += data_byte;
+                       DBG("buf=%p dlen=%d diff=%d", buf, dlen, diff);
+               }
+       }
+
+       /*
+        * For single Long read, if the requested rlen < 10,
+        * we need to shift the start position of rx
+        * data buffer to skip the bytes which are not
+        * updated.
+        */
+       if (pkt_size < 10 && !short_response)
+               buf = msm_host->rx_buf + (10 - rlen);
+       else
+               buf = msm_host->rx_buf;
+
+       cmd = buf[0];
+       switch (cmd) {
+       case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
+               pr_err("%s: rx ACK_ERR_PACLAGE\n", __func__);
+               ret = 0;
+       case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
+       case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
+               ret = dsi_short_read1_resp(buf, msg);
+               break;
+       case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
+       case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
+               ret = dsi_short_read2_resp(buf, msg);
+               break;
+       case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
+       case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
+               ret = dsi_long_read_resp(buf, msg);
+               break;
+       default:
+               pr_warn("%s:Invalid response cmd\n", __func__);
+               ret = 0;
+       }
+
+       return ret;
+}
+
+void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host, u32 iova, u32 len)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       dsi_write(msm_host, REG_DSI_DMA_BASE, iova);
+       dsi_write(msm_host, REG_DSI_DMA_LEN, len);
+       dsi_write(msm_host, REG_DSI_TRIG_DMA, 1);
+
+       /* Make sure trigger happens */
+       wmb();
+}
+
+int msm_dsi_host_enable(struct mipi_dsi_host *host)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       dsi_op_mode_config(msm_host,
+               !!(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO), true);
+
+       /* TODO: clock should be turned off for command mode,
+        * and only turned on before MDP START.
+        * This part of code should be enabled once mdp driver support it.
+        */
+       /* if (msm_panel->mode == MSM_DSI_CMD_MODE)
+               dsi_clk_ctrl(msm_host, 0); */
+
+       return 0;
+}
+
+int msm_dsi_host_disable(struct mipi_dsi_host *host)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       dsi_op_mode_config(msm_host,
+               !!(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO), false);
+
+       /* Since we have disabled INTF, the video engine won't stop so that
+        * the cmd engine will be blocked.
+        * Reset to disable video engine so that we can send off cmd.
+        */
+       dsi_sw_reset(msm_host);
+
+       return 0;
+}
+
+int msm_dsi_host_power_on(struct mipi_dsi_host *host)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+       u32 clk_pre = 0, clk_post = 0;
+       int ret = 0;
+
+       mutex_lock(&msm_host->dev_mutex);
+       if (msm_host->power_on) {
+               DBG("dsi host already on");
+               goto unlock_ret;
+       }
+
+       ret = dsi_calc_clk_rate(msm_host);
+       if (ret) {
+               pr_err("%s: unable to calc clk rate, %d\n", __func__, ret);
+               goto unlock_ret;
+       }
+
+       ret = dsi_host_regulator_enable(msm_host);
+       if (ret) {
+               pr_err("%s:Failed to enable vregs.ret=%d\n",
+                       __func__, ret);
+               goto unlock_ret;
+       }
+
+       ret = dsi_bus_clk_enable(msm_host);
+       if (ret) {
+               pr_err("%s: failed to enable bus clocks, %d\n", __func__, ret);
+               goto fail_disable_reg;
+       }
+
+       dsi_phy_sw_reset(msm_host);
+       ret = msm_dsi_manager_phy_enable(msm_host->id,
+                                       msm_host->byte_clk_rate * 8,
+                                       clk_get_rate(msm_host->esc_clk),
+                                       &clk_pre, &clk_post);
+       dsi_bus_clk_disable(msm_host);
+       if (ret) {
+               pr_err("%s: failed to enable phy, %d\n", __func__, ret);
+               goto fail_disable_reg;
+       }
+
+       ret = dsi_clk_ctrl(msm_host, 1);
+       if (ret) {
+               pr_err("%s: failed to enable clocks. ret=%d\n", __func__, ret);
+               goto fail_disable_reg;
+       }
+
+       dsi_timing_setup(msm_host);
+       dsi_sw_reset(msm_host);
+       dsi_ctrl_config(msm_host, true, clk_pre, clk_post);
+
+       if (msm_host->disp_en_gpio)
+               gpiod_set_value(msm_host->disp_en_gpio, 1);
+
+       msm_host->power_on = true;
+       mutex_unlock(&msm_host->dev_mutex);
+
+       return 0;
+
+fail_disable_reg:
+       dsi_host_regulator_disable(msm_host);
+unlock_ret:
+       mutex_unlock(&msm_host->dev_mutex);
+       return ret;
+}
+
+int msm_dsi_host_power_off(struct mipi_dsi_host *host)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       mutex_lock(&msm_host->dev_mutex);
+       if (!msm_host->power_on) {
+               DBG("dsi host already off");
+               goto unlock_ret;
+       }
+
+       dsi_ctrl_config(msm_host, false, 0, 0);
+
+       if (msm_host->disp_en_gpio)
+               gpiod_set_value(msm_host->disp_en_gpio, 0);
+
+       msm_dsi_manager_phy_disable(msm_host->id);
+
+       dsi_clk_ctrl(msm_host, 0);
+
+       dsi_host_regulator_disable(msm_host);
+
+       DBG("-");
+
+       msm_host->power_on = false;
+
+unlock_ret:
+       mutex_unlock(&msm_host->dev_mutex);
+       return 0;
+}
+
+int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
+                                       struct drm_display_mode *mode)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+       if (msm_host->mode) {
+               drm_mode_destroy(msm_host->dev, msm_host->mode);
+               msm_host->mode = NULL;
+       }
+
+       msm_host->mode = drm_mode_duplicate(msm_host->dev, mode);
+       if (IS_ERR(msm_host->mode)) {
+               pr_err("%s: cannot duplicate mode\n", __func__);
+               return PTR_ERR(msm_host->mode);
+       }
+
+       return 0;
+}
+
+struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host,
+                               unsigned long *panel_flags)
+{
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+       struct drm_panel *panel;
+
+       panel = of_drm_find_panel(msm_host->panel_node);
+       if (panel_flags)
+                       *panel_flags = msm_host->mode_flags;
+
+       return panel;
+}
+
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
new file mode 100644 (file)
index 0000000..ee3ebca
--- /dev/null
@@ -0,0 +1,705 @@
+/*
+ * Copyright (c) 2015, 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 "msm_kms.h"
+#include "dsi.h"
+
+struct msm_dsi_manager {
+       struct msm_dsi *dsi[DSI_MAX];
+
+       bool is_dual_panel;
+       bool is_sync_needed;
+       int master_panel_id;
+};
+
+static struct msm_dsi_manager msm_dsim_glb;
+
+#define IS_DUAL_PANEL()                (msm_dsim_glb.is_dual_panel)
+#define IS_SYNC_NEEDED()       (msm_dsim_glb.is_sync_needed)
+#define IS_MASTER_PANEL(id)    (msm_dsim_glb.master_panel_id == id)
+
+static inline struct msm_dsi *dsi_mgr_get_dsi(int id)
+{
+       return msm_dsim_glb.dsi[id];
+}
+
+static inline struct msm_dsi *dsi_mgr_get_other_dsi(int id)
+{
+       return msm_dsim_glb.dsi[(id + 1) % DSI_MAX];
+}
+
+static int dsi_mgr_parse_dual_panel(struct device_node *np, int id)
+{
+       struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
+
+       /* We assume 2 dsi nodes have the same information of dual-panel and
+        * sync-mode, and only one node specifies master in case of dual mode.
+        */
+       if (!msm_dsim->is_dual_panel)
+               msm_dsim->is_dual_panel = of_property_read_bool(
+                                               np, "qcom,dual-panel-mode");
+
+       if (msm_dsim->is_dual_panel) {
+               if (of_property_read_bool(np, "qcom,master-panel"))
+                       msm_dsim->master_panel_id = id;
+               if (!msm_dsim->is_sync_needed)
+                       msm_dsim->is_sync_needed = of_property_read_bool(
+                                       np, "qcom,sync-dual-panel");
+       }
+
+       return 0;
+}
+
+struct dsi_connector {
+       struct drm_connector base;
+       int id;
+};
+
+struct dsi_bridge {
+       struct drm_bridge base;
+       int id;
+};
+
+#define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
+#define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
+
+static inline int dsi_mgr_connector_get_id(struct drm_connector *connector)
+{
+       struct dsi_connector *dsi_connector = to_dsi_connector(connector);
+       return dsi_connector->id;
+}
+
+static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
+{
+       struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
+       return dsi_bridge->id;
+}
+
+static enum drm_connector_status dsi_mgr_connector_detect(
+               struct drm_connector *connector, bool force)
+{
+       int id = dsi_mgr_connector_get_id(connector);
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
+       struct msm_drm_private *priv = connector->dev->dev_private;
+       struct msm_kms *kms = priv->kms;
+
+       DBG("id=%d", id);
+       if (!msm_dsi->panel) {
+               msm_dsi->panel = msm_dsi_host_get_panel(msm_dsi->host,
+                                               &msm_dsi->panel_flags);
+
+               /* There is only 1 panel in the global panel list
+                * for dual panel mode. Therefore slave dsi should get
+                * the drm_panel instance from master dsi, and
+                * keep using the panel flags got from the current DSI link.
+                */
+               if (!msm_dsi->panel && IS_DUAL_PANEL() &&
+                       !IS_MASTER_PANEL(id) && other_dsi)
+                       msm_dsi->panel = msm_dsi_host_get_panel(
+                                       other_dsi->host, NULL);
+
+               if (msm_dsi->panel && IS_DUAL_PANEL())
+                       drm_object_attach_property(&connector->base,
+                               connector->dev->mode_config.tile_property, 0);
+
+               /* Set split display info to kms once dual panel is connected
+                * to both hosts
+                */
+               if (msm_dsi->panel && IS_DUAL_PANEL() &&
+                       other_dsi && other_dsi->panel) {
+                       bool cmd_mode = !(msm_dsi->panel_flags &
+                                               MIPI_DSI_MODE_VIDEO);
+                       struct drm_encoder *encoder = msm_dsi_get_encoder(
+                                       dsi_mgr_get_dsi(DSI_ENCODER_MASTER));
+                       struct drm_encoder *slave_enc = msm_dsi_get_encoder(
+                                       dsi_mgr_get_dsi(DSI_ENCODER_SLAVE));
+
+                       if (kms->funcs->set_split_display)
+                               kms->funcs->set_split_display(kms, encoder,
+                                                       slave_enc, cmd_mode);
+                       else
+                               pr_err("mdp does not support dual panel\n");
+               }
+       }
+
+       return msm_dsi->panel ? connector_status_connected :
+               connector_status_disconnected;
+}
+
+static void dsi_mgr_connector_destroy(struct drm_connector *connector)
+{
+       DBG("");
+       drm_connector_unregister(connector);
+       drm_connector_cleanup(connector);
+}
+
+static void dsi_dual_connector_fix_modes(struct drm_connector *connector)
+{
+       struct drm_display_mode *mode, *m;
+
+       /* Only support left-right mode */
+       list_for_each_entry_safe(mode, m, &connector->probed_modes, head) {
+               mode->clock >>= 1;
+               mode->hdisplay >>= 1;
+               mode->hsync_start >>= 1;
+               mode->hsync_end >>= 1;
+               mode->htotal >>= 1;
+               drm_mode_set_name(mode);
+       }
+}
+
+static int dsi_dual_connector_tile_init(
+                       struct drm_connector *connector, int id)
+{
+       struct drm_display_mode *mode;
+       /* Fake topology id */
+       char topo_id[8] = {'M', 'S', 'M', 'D', 'U', 'D', 'S', 'I'};
+
+       if (connector->tile_group) {
+               DBG("Tile property has been initialized");
+               return 0;
+       }
+
+       /* Use the first mode only for now */
+       mode = list_first_entry(&connector->probed_modes,
+                               struct drm_display_mode,
+                               head);
+       if (!mode)
+               return -EINVAL;
+
+       connector->tile_group = drm_mode_get_tile_group(
+                                       connector->dev, topo_id);
+       if (!connector->tile_group)
+               connector->tile_group = drm_mode_create_tile_group(
+                                       connector->dev, topo_id);
+       if (!connector->tile_group) {
+               pr_err("%s: failed to create tile group\n", __func__);
+               return -ENOMEM;
+       }
+
+       connector->has_tile = true;
+       connector->tile_is_single_monitor = true;
+
+       /* mode has been fixed */
+       connector->tile_h_size = mode->hdisplay;
+       connector->tile_v_size = mode->vdisplay;
+
+       /* Only support left-right mode */
+       connector->num_h_tile = 2;
+       connector->num_v_tile = 1;
+
+       connector->tile_v_loc = 0;
+       connector->tile_h_loc = (id == DSI_RIGHT) ? 1 : 0;
+
+       return 0;
+}
+
+static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
+{
+       int id = dsi_mgr_connector_get_id(connector);
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct drm_panel *panel = msm_dsi->panel;
+       int ret, num;
+
+       if (!panel)
+               return 0;
+
+       /* Since we have 2 connectors, but only 1 drm_panel in dual DSI mode,
+        * panel should not attach to any connector.
+        * Only temporarily attach panel to the current connector here,
+        * to let panel set mode to this connector.
+        */
+       drm_panel_attach(panel, connector);
+       num = drm_panel_get_modes(panel);
+       drm_panel_detach(panel);
+       if (!num)
+               return 0;
+
+       if (IS_DUAL_PANEL()) {
+               /* report half resolution to user */
+               dsi_dual_connector_fix_modes(connector);
+               ret = dsi_dual_connector_tile_init(connector, id);
+               if (ret)
+                       return ret;
+               ret = drm_mode_connector_set_tile_property(connector);
+               if (ret) {
+                       pr_err("%s: set tile property failed, %d\n",
+                                       __func__, ret);
+                       return ret;
+               }
+       }
+
+       return num;
+}
+
+static int dsi_mgr_connector_mode_valid(struct drm_connector *connector,
+                               struct drm_display_mode *mode)
+{
+       int id = dsi_mgr_connector_get_id(connector);
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct drm_encoder *encoder = msm_dsi_get_encoder(msm_dsi);
+       struct msm_drm_private *priv = connector->dev->dev_private;
+       struct msm_kms *kms = priv->kms;
+       long actual, requested;
+
+       DBG("");
+       requested = 1000 * mode->clock;
+       actual = kms->funcs->round_pixclk(kms, requested, encoder);
+
+       DBG("requested=%ld, actual=%ld", requested, actual);
+       if (actual != requested)
+               return MODE_CLOCK_RANGE;
+
+       return MODE_OK;
+}
+
+static struct drm_encoder *
+dsi_mgr_connector_best_encoder(struct drm_connector *connector)
+{
+       int id = dsi_mgr_connector_get_id(connector);
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+
+       DBG("");
+       return msm_dsi_get_encoder(msm_dsi);
+}
+
+static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
+{
+       int id = dsi_mgr_bridge_get_id(bridge);
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
+       struct mipi_dsi_host *host = msm_dsi->host;
+       struct drm_panel *panel = msm_dsi->panel;
+       bool is_dual_panel = IS_DUAL_PANEL();
+       int ret;
+
+       DBG("id=%d", id);
+       if (!panel || (is_dual_panel && (DSI_1 == id)))
+               return;
+
+       ret = msm_dsi_host_power_on(host);
+       if (ret) {
+               pr_err("%s: power on host %d failed, %d\n", __func__, id, ret);
+               goto host_on_fail;
+       }
+
+       if (is_dual_panel && msm_dsi1) {
+               ret = msm_dsi_host_power_on(msm_dsi1->host);
+               if (ret) {
+                       pr_err("%s: power on host1 failed, %d\n",
+                                                       __func__, ret);
+                       goto host1_on_fail;
+               }
+       }
+
+       /* Always call panel functions once, because even for dual panels,
+        * there is only one drm_panel instance.
+        */
+       ret = drm_panel_prepare(panel);
+       if (ret) {
+               pr_err("%s: prepare panel %d failed, %d\n", __func__, id, ret);
+               goto panel_prep_fail;
+       }
+
+       ret = msm_dsi_host_enable(host);
+       if (ret) {
+               pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
+               goto host_en_fail;
+       }
+
+       if (is_dual_panel && msm_dsi1) {
+               ret = msm_dsi_host_enable(msm_dsi1->host);
+               if (ret) {
+                       pr_err("%s: enable host1 failed, %d\n", __func__, ret);
+                       goto host1_en_fail;
+               }
+       }
+
+       ret = drm_panel_enable(panel);
+       if (ret) {
+               pr_err("%s: enable panel %d failed, %d\n", __func__, id, ret);
+               goto panel_en_fail;
+       }
+
+       return;
+
+panel_en_fail:
+       if (is_dual_panel && msm_dsi1)
+               msm_dsi_host_disable(msm_dsi1->host);
+host1_en_fail:
+       msm_dsi_host_disable(host);
+host_en_fail:
+       drm_panel_unprepare(panel);
+panel_prep_fail:
+       if (is_dual_panel && msm_dsi1)
+               msm_dsi_host_power_off(msm_dsi1->host);
+host1_on_fail:
+       msm_dsi_host_power_off(host);
+host_on_fail:
+       return;
+}
+
+static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
+{
+       DBG("");
+}
+
+static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
+{
+       DBG("");
+}
+
+static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
+{
+       int id = dsi_mgr_bridge_get_id(bridge);
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
+       struct mipi_dsi_host *host = msm_dsi->host;
+       struct drm_panel *panel = msm_dsi->panel;
+       bool is_dual_panel = IS_DUAL_PANEL();
+       int ret;
+
+       DBG("id=%d", id);
+
+       if (!panel || (is_dual_panel && (DSI_1 == id)))
+               return;
+
+       ret = drm_panel_disable(panel);
+       if (ret)
+               pr_err("%s: Panel %d OFF failed, %d\n", __func__, id, ret);
+
+       ret = msm_dsi_host_disable(host);
+       if (ret)
+               pr_err("%s: host %d disable failed, %d\n", __func__, id, ret);
+
+       if (is_dual_panel && msm_dsi1) {
+               ret = msm_dsi_host_disable(msm_dsi1->host);
+               if (ret)
+                       pr_err("%s: host1 disable failed, %d\n", __func__, ret);
+       }
+
+       ret = drm_panel_unprepare(panel);
+       if (ret)
+               pr_err("%s: Panel %d unprepare failed,%d\n", __func__, id, ret);
+
+       ret = msm_dsi_host_power_off(host);
+       if (ret)
+               pr_err("%s: host %d power off failed,%d\n", __func__, id, ret);
+
+       if (is_dual_panel && msm_dsi1) {
+               ret = msm_dsi_host_power_off(msm_dsi1->host);
+               if (ret)
+                       pr_err("%s: host1 power off failed, %d\n",
+                                                               __func__, ret);
+       }
+}
+
+static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       int id = dsi_mgr_bridge_get_id(bridge);
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
+       struct mipi_dsi_host *host = msm_dsi->host;
+       bool is_dual_panel = IS_DUAL_PANEL();
+
+       DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
+                       mode->base.id, mode->name,
+                       mode->vrefresh, mode->clock,
+                       mode->hdisplay, mode->hsync_start,
+                       mode->hsync_end, mode->htotal,
+                       mode->vdisplay, mode->vsync_start,
+                       mode->vsync_end, mode->vtotal,
+                       mode->type, mode->flags);
+
+       if (is_dual_panel && (DSI_1 == id))
+               return;
+
+       msm_dsi_host_set_display_mode(host, adjusted_mode);
+       if (is_dual_panel && other_dsi)
+               msm_dsi_host_set_display_mode(other_dsi->host, adjusted_mode);
+}
+
+static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
+       .dpms = drm_atomic_helper_connector_dpms,
+       .detect = dsi_mgr_connector_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = dsi_mgr_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 dsi_mgr_conn_helper_funcs = {
+       .get_modes = dsi_mgr_connector_get_modes,
+       .mode_valid = dsi_mgr_connector_mode_valid,
+       .best_encoder = dsi_mgr_connector_best_encoder,
+};
+
+static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
+       .pre_enable = dsi_mgr_bridge_pre_enable,
+       .enable = dsi_mgr_bridge_enable,
+       .disable = dsi_mgr_bridge_disable,
+       .post_disable = dsi_mgr_bridge_post_disable,
+       .mode_set = dsi_mgr_bridge_mode_set,
+};
+
+/* initialize connector */
+struct drm_connector *msm_dsi_manager_connector_init(u8 id)
+{
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct drm_connector *connector = NULL;
+       struct dsi_connector *dsi_connector;
+       int ret;
+
+       dsi_connector = devm_kzalloc(msm_dsi->dev->dev,
+                               sizeof(*dsi_connector), GFP_KERNEL);
+       if (!dsi_connector) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       dsi_connector->id = id;
+
+       connector = &dsi_connector->base;
+
+       ret = drm_connector_init(msm_dsi->dev, connector,
+                       &dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI);
+       if (ret)
+               goto fail;
+
+       drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs);
+
+       /* Enable HPD to let hpd event is handled
+        * when panel is attached to the host.
+        */
+       connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+       /* Display driver doesn't support interlace now. */
+       connector->interlace_allowed = 0;
+       connector->doublescan_allowed = 0;
+
+       ret = drm_connector_register(connector);
+       if (ret)
+               goto fail;
+
+       return connector;
+
+fail:
+       if (connector)
+               dsi_mgr_connector_destroy(connector);
+
+       return ERR_PTR(ret);
+}
+
+/* initialize bridge */
+struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
+{
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct drm_bridge *bridge = NULL;
+       struct dsi_bridge *dsi_bridge;
+       int ret;
+
+       dsi_bridge = devm_kzalloc(msm_dsi->dev->dev,
+                               sizeof(*dsi_bridge), GFP_KERNEL);
+       if (!dsi_bridge) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       dsi_bridge->id = id;
+
+       bridge = &dsi_bridge->base;
+       bridge->funcs = &dsi_mgr_bridge_funcs;
+
+       ret = drm_bridge_attach(msm_dsi->dev, bridge);
+       if (ret)
+               goto fail;
+
+       return bridge;
+
+fail:
+       if (bridge)
+               msm_dsi_manager_bridge_destroy(bridge);
+
+       return ERR_PTR(ret);
+}
+
+void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)
+{
+}
+
+int msm_dsi_manager_phy_enable(int id,
+               const unsigned long bit_rate, const unsigned long esc_rate,
+               u32 *clk_pre, u32 *clk_post)
+{
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct msm_dsi_phy *phy = msm_dsi->phy;
+       int ret;
+
+       ret = msm_dsi_phy_enable(phy, IS_DUAL_PANEL(), bit_rate, esc_rate);
+       if (ret)
+               return ret;
+
+       msm_dsi->phy_enabled = true;
+       msm_dsi_phy_get_clk_pre_post(phy, clk_pre, clk_post);
+
+       return 0;
+}
+
+void msm_dsi_manager_phy_disable(int id)
+{
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
+       struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
+       struct msm_dsi_phy *phy = msm_dsi->phy;
+
+       /* disable DSI phy
+        * In dual-dsi configuration, the phy should be disabled for the
+        * first controller only when the second controller is disabled.
+        */
+       msm_dsi->phy_enabled = false;
+       if (IS_DUAL_PANEL() && mdsi && sdsi) {
+               if (!mdsi->phy_enabled && !sdsi->phy_enabled) {
+                       msm_dsi_phy_disable(sdsi->phy);
+                       msm_dsi_phy_disable(mdsi->phy);
+               }
+       } else {
+               msm_dsi_phy_disable(phy);
+       }
+}
+
+int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg)
+{
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0);
+       struct mipi_dsi_host *host = msm_dsi->host;
+       bool is_read = (msg->rx_buf && msg->rx_len);
+       bool need_sync = (IS_SYNC_NEEDED() && !is_read);
+       int ret;
+
+       if (!msg->tx_buf || !msg->tx_len)
+               return 0;
+
+       /* In dual master case, panel requires the same commands sent to
+        * both DSI links. Host issues the command trigger to both links
+        * when DSI_1 calls the cmd transfer function, no matter it happens
+        * before or after DSI_0 cmd transfer.
+        */
+       if (need_sync && (id == DSI_0))
+               return is_read ? msg->rx_len : msg->tx_len;
+
+       if (need_sync && msm_dsi0) {
+               ret = msm_dsi_host_xfer_prepare(msm_dsi0->host, msg);
+               if (ret) {
+                       pr_err("%s: failed to prepare non-trigger host, %d\n",
+                               __func__, ret);
+                       return ret;
+               }
+       }
+       ret = msm_dsi_host_xfer_prepare(host, msg);
+       if (ret) {
+               pr_err("%s: failed to prepare host, %d\n", __func__, ret);
+               goto restore_host0;
+       }
+
+       ret = is_read ? msm_dsi_host_cmd_rx(host, msg) :
+                       msm_dsi_host_cmd_tx(host, msg);
+
+       msm_dsi_host_xfer_restore(host, msg);
+
+restore_host0:
+       if (need_sync && msm_dsi0)
+               msm_dsi_host_xfer_restore(msm_dsi0->host, msg);
+
+       return ret;
+}
+
+bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len)
+{
+       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+       struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0);
+       struct mipi_dsi_host *host = msm_dsi->host;
+
+       if (IS_SYNC_NEEDED() && (id == DSI_0))
+               return false;
+
+       if (IS_SYNC_NEEDED() && msm_dsi0)
+               msm_dsi_host_cmd_xfer_commit(msm_dsi0->host, iova, len);
+
+       msm_dsi_host_cmd_xfer_commit(host, iova, len);
+
+       return true;
+}
+
+int msm_dsi_manager_register(struct msm_dsi *msm_dsi)
+{
+       struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
+       int id = msm_dsi->id;
+       struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
+       int ret;
+
+       if (id > DSI_MAX) {
+               pr_err("%s: invalid id %d\n", __func__, id);
+               return -EINVAL;
+       }
+
+       if (msm_dsim->dsi[id]) {
+               pr_err("%s: dsi%d already registered\n", __func__, id);
+               return -EBUSY;
+       }
+
+       msm_dsim->dsi[id] = msm_dsi;
+
+       ret = dsi_mgr_parse_dual_panel(msm_dsi->pdev->dev.of_node, id);
+       if (ret) {
+               pr_err("%s: failed to parse dual panel info\n", __func__);
+               return ret;
+       }
+
+       if (!IS_DUAL_PANEL()) {
+               ret = msm_dsi_host_register(msm_dsi->host, true);
+       } else if (!other_dsi) {
+               return 0;
+       } else {
+               struct msm_dsi *mdsi = IS_MASTER_PANEL(id) ?
+                                       msm_dsi : other_dsi;
+               struct msm_dsi *sdsi = IS_MASTER_PANEL(id) ?
+                                       other_dsi : msm_dsi;
+               /* Register slave host first, so that slave DSI device
+                * has a chance to probe, and do not block the master
+                * DSI device's probe.
+                * Also, do not check defer for the slave host,
+                * because only master DSI device adds the panel to global
+                * panel list. The panel's device is the master DSI device.
+                */
+               ret = msm_dsi_host_register(sdsi->host, false);
+               if (ret)
+                       return ret;
+               ret = msm_dsi_host_register(mdsi->host, true);
+       }
+
+       return ret;
+}
+
+void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi)
+{
+       struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
+
+       if (msm_dsi->host)
+               msm_dsi_host_unregister(msm_dsi->host);
+       msm_dsim->dsi[msm_dsi->id] = NULL;
+}
+
diff --git a/drivers/gpu/drm/msm/dsi/dsi_phy.c b/drivers/gpu/drm/msm/dsi/dsi_phy.c
new file mode 100644 (file)
index 0000000..f0cea89
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2015, 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 "dsi.h"
+#include "dsi.xml.h"
+
+#define dsi_phy_read(offset) msm_readl((offset))
+#define dsi_phy_write(offset, data) msm_writel((data), (offset))
+
+struct dsi_dphy_timing {
+       u32 clk_pre;
+       u32 clk_post;
+       u32 clk_zero;
+       u32 clk_trail;
+       u32 clk_prepare;
+       u32 hs_exit;
+       u32 hs_zero;
+       u32 hs_prepare;
+       u32 hs_trail;
+       u32 hs_rqst;
+       u32 ta_go;
+       u32 ta_sure;
+       u32 ta_get;
+};
+
+struct msm_dsi_phy {
+       void __iomem *base;
+       void __iomem *reg_base;
+       int id;
+       struct dsi_dphy_timing timing;
+       int (*enable)(struct msm_dsi_phy *phy, bool is_dual_panel,
+               const unsigned long bit_rate, const unsigned long esc_rate);
+       int (*disable)(struct msm_dsi_phy *phy);
+};
+
+#define S_DIV_ROUND_UP(n, d)   \
+       (((n) >= 0) ? (((n) + (d) - 1) / (d)) : (((n) - (d) + 1) / (d)))
+
+static inline s32 linear_inter(s32 tmax, s32 tmin, s32 percent,
+                               s32 min_result, bool even)
+{
+       s32 v;
+       v = (tmax - tmin) * percent;
+       v = S_DIV_ROUND_UP(v, 100) + tmin;
+       if (even && (v & 0x1))
+               return max_t(s32, min_result, v - 1);
+       else
+               return max_t(s32, min_result, v);
+}
+
+static void dsi_dphy_timing_calc_clk_zero(struct dsi_dphy_timing *timing,
+                                       s32 ui, s32 coeff, s32 pcnt)
+{
+       s32 tmax, tmin, clk_z;
+       s32 temp;
+
+       /* reset */
+       temp = 300 * coeff - ((timing->clk_prepare >> 1) + 1) * 2 * ui;
+       tmin = S_DIV_ROUND_UP(temp, ui) - 2;
+       if (tmin > 255) {
+               tmax = 511;
+               clk_z = linear_inter(2 * tmin, tmin, pcnt, 0, true);
+       } else {
+               tmax = 255;
+               clk_z = linear_inter(tmax, tmin, pcnt, 0, true);
+       }
+
+       /* adjust */
+       temp = (timing->hs_rqst + timing->clk_prepare + clk_z) & 0x7;
+       timing->clk_zero = clk_z + 8 - temp;
+}
+
+static int dsi_dphy_timing_calc(struct dsi_dphy_timing *timing,
+       const unsigned long bit_rate, const unsigned long esc_rate)
+{
+       s32 ui, lpx;
+       s32 tmax, tmin;
+       s32 pcnt0 = 10;
+       s32 pcnt1 = (bit_rate > 1200000000) ? 15 : 10;
+       s32 pcnt2 = 10;
+       s32 pcnt3 = (bit_rate > 180000000) ? 10 : 40;
+       s32 coeff = 1000; /* Precision, should avoid overflow */
+       s32 temp;
+
+       if (!bit_rate || !esc_rate)
+               return -EINVAL;
+
+       ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
+       lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000);
+
+       tmax = S_DIV_ROUND_UP(95 * coeff, ui) - 2;
+       tmin = S_DIV_ROUND_UP(38 * coeff, ui) - 2;
+       timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, true);
+
+       temp = lpx / ui;
+       if (temp & 0x1)
+               timing->hs_rqst = temp;
+       else
+               timing->hs_rqst = max_t(s32, 0, temp - 2);
+
+       /* Calculate clk_zero after clk_prepare and hs_rqst */
+       dsi_dphy_timing_calc_clk_zero(timing, ui, coeff, pcnt2);
+
+       temp = 105 * coeff + 12 * ui - 20 * coeff;
+       tmax = S_DIV_ROUND_UP(temp, ui) - 2;
+       tmin = S_DIV_ROUND_UP(60 * coeff, ui) - 2;
+       timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, true);
+
+       temp = 85 * coeff + 6 * ui;
+       tmax = S_DIV_ROUND_UP(temp, ui) - 2;
+       temp = 40 * coeff + 4 * ui;
+       tmin = S_DIV_ROUND_UP(temp, ui) - 2;
+       timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, true);
+
+       tmax = 255;
+       temp = ((timing->hs_prepare >> 1) + 1) * 2 * ui + 2 * ui;
+       temp = 145 * coeff + 10 * ui - temp;
+       tmin = S_DIV_ROUND_UP(temp, ui) - 2;
+       timing->hs_zero = linear_inter(tmax, tmin, pcnt2, 24, true);
+
+       temp = 105 * coeff + 12 * ui - 20 * coeff;
+       tmax = S_DIV_ROUND_UP(temp, ui) - 2;
+       temp = 60 * coeff + 4 * ui;
+       tmin = DIV_ROUND_UP(temp, ui) - 2;
+       timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, true);
+
+       tmax = 255;
+       tmin = S_DIV_ROUND_UP(100 * coeff, ui) - 2;
+       timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, true);
+
+       tmax = 63;
+       temp = ((timing->hs_exit >> 1) + 1) * 2 * ui;
+       temp = 60 * coeff + 52 * ui - 24 * ui - temp;
+       tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
+       timing->clk_post = linear_inter(tmax, tmin, pcnt2, 0, false);
+
+       tmax = 63;
+       temp = ((timing->clk_prepare >> 1) + 1) * 2 * ui;
+       temp += ((timing->clk_zero >> 1) + 1) * 2 * ui;
+       temp += 8 * ui + lpx;
+       tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
+       if (tmin > tmax) {
+               temp = linear_inter(2 * tmax, tmin, pcnt2, 0, false) >> 1;
+               timing->clk_pre = temp >> 1;
+               temp = (2 * tmax - tmin) * pcnt2;
+       } else {
+               timing->clk_pre = linear_inter(tmax, tmin, pcnt2, 0, false);
+       }
+
+       timing->ta_go = 3;
+       timing->ta_sure = 0;
+       timing->ta_get = 4;
+
+       DBG("PHY timings: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
+               timing->clk_pre, timing->clk_post, timing->clk_zero,
+               timing->clk_trail, timing->clk_prepare, timing->hs_exit,
+               timing->hs_zero, timing->hs_prepare, timing->hs_trail,
+               timing->hs_rqst);
+
+       return 0;
+}
+
+static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable)
+{
+       void __iomem *base = phy->reg_base;
+
+       if (!enable) {
+               dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0);
+               return;
+       }
+
+       dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x0);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 1);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_5, 0);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_3, 0);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_2, 0x3);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_1, 0x9);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x7);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_4, 0x20);
+}
+
+static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
+               const unsigned long bit_rate, const unsigned long esc_rate)
+{
+       struct dsi_dphy_timing *timing = &phy->timing;
+       int i;
+       void __iomem *base = phy->base;
+
+       DBG("");
+
+       if (dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) {
+               pr_err("%s: D-PHY timing calculation failed\n", __func__);
+               return -EINVAL;
+       }
+
+       dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_0, 0xff);
+
+       dsi_28nm_phy_regulator_ctrl(phy, true);
+
+       dsi_phy_write(base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x00);
+
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_0,
+               DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_1,
+               DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_2,
+               DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare));
+       if (timing->clk_zero & BIT(8))
+               dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_3,
+                       DSI_28nm_PHY_TIMING_CTRL_3_CLK_ZERO_8);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_4,
+               DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_5,
+               DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_6,
+               DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_7,
+               DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_8,
+               DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_9,
+               DSI_28nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) |
+               DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_10,
+               DSI_28nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get));
+       dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_11,
+               DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0));
+
+       dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_1, 0x00);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
+
+       dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_1, 0x6);
+
+       for (i = 0; i < 4; i++) {
+               dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_0(i), 0);
+               dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_1(i), 0);
+               dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_2(i), 0);
+               dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_3(i), 0);
+               dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_DATAPATH(i), 0);
+               dsi_phy_write(base + REG_DSI_28nm_PHY_LN_DEBUG_SEL(i), 0);
+               dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_0(i), 0x1);
+               dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_1(i), 0x97);
+       }
+       dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(0), 0);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(1), 0x5);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(2), 0xa);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(3), 0xf);
+
+       dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_CFG_1, 0xc0);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR0, 0x1);
+       dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR1, 0xbb);
+
+       dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
+
+       if (is_dual_panel && (phy->id != DSI_CLOCK_MASTER))
+               dsi_phy_write(base + REG_DSI_28nm_PHY_GLBL_TEST_CTRL, 0x00);
+       else
+               dsi_phy_write(base + REG_DSI_28nm_PHY_GLBL_TEST_CTRL, 0x01);
+
+       return 0;
+}
+
+static int dsi_28nm_phy_disable(struct msm_dsi_phy *phy)
+{
+       dsi_phy_write(phy->base + REG_DSI_28nm_PHY_CTRL_0, 0);
+       dsi_28nm_phy_regulator_ctrl(phy, false);
+
+       /*
+        * Wait for the registers writes to complete in order to
+        * ensure that the phy is completely disabled
+        */
+       wmb();
+
+       return 0;
+}
+
+#define dsi_phy_func_init(name)        \
+       do {    \
+               phy->enable = dsi_##name##_phy_enable;  \
+               phy->disable = dsi_##name##_phy_disable;        \
+       } while (0)
+
+struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev,
+                       enum msm_dsi_phy_type type, int id)
+{
+       struct msm_dsi_phy *phy;
+
+       phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
+       if (!phy)
+               return NULL;
+
+       phy->base = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
+       if (IS_ERR_OR_NULL(phy->base)) {
+               pr_err("%s: failed to map phy base\n", __func__);
+               return NULL;
+       }
+       phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator", "DSI_PHY_REG");
+       if (IS_ERR_OR_NULL(phy->reg_base)) {
+               pr_err("%s: failed to map phy regulator base\n", __func__);
+               return NULL;
+       }
+
+       switch (type) {
+       case MSM_DSI_PHY_28NM:
+               dsi_phy_func_init(28nm);
+               break;
+       default:
+               pr_err("%s: unsupported type, %d\n", __func__, type);
+               return NULL;
+       }
+
+       phy->id = id;
+
+       return phy;
+}
+
+int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
+       const unsigned long bit_rate, const unsigned long esc_rate)
+{
+       if (!phy || !phy->enable)
+               return -EINVAL;
+       return phy->enable(phy, is_dual_panel, bit_rate, esc_rate);
+}
+
+int msm_dsi_phy_disable(struct msm_dsi_phy *phy)
+{
+       if (!phy || !phy->disable)
+               return -EINVAL;
+       return phy->disable(phy);
+}
+
+void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy,
+       u32 *clk_pre, u32 *clk_post)
+{
+       if (!phy)
+               return;
+       if (clk_pre)
+               *clk_pre = phy->timing.clk_pre;
+       if (clk_post)
+               *clk_post = phy->timing.clk_post;
+}
+
index eeed006eed1337a6c07c62e0cc62d944b95fce83..6997ec636c6d473413227f0701e3f1c72b94988c 100644 (file)
@@ -53,6 +53,23 @@ struct pll_rate {
 
 /* NOTE: keep sorted highest freq to lowest: */
 static const struct pll_rate freqtbl[] = {
+       { 154000000, {
+               { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG    },
+               { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
+               { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
+               { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0   },
+               { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1   },
+               { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2   },
+               { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3   },
+               { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4   },
+               { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5   },
+               { 0x0d, REG_HDMI_8960_PHY_PLL_SDM_CFG0      },
+               { 0x4d, REG_HDMI_8960_PHY_PLL_SDM_CFG1      },
+               { 0x5e, REG_HDMI_8960_PHY_PLL_SDM_CFG2      },
+               { 0x42, REG_HDMI_8960_PHY_PLL_SDM_CFG3      },
+               { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4      },
+               { 0, 0 } }
+       },
        /* 1080p60/1080p50 case */
        { 148500000, {
                { 0x02, REG_HDMI_8960_PHY_PLL_REFCLK_CFG    },
@@ -112,6 +129,23 @@ static const struct pll_rate freqtbl[] = {
                { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2   },
                { 0, 0 } }
        },
+       { 74176000, {
+               { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG    },
+               { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
+               { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
+               { 0xe5, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0   },
+               { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1   },
+               { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2   },
+               { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3   },
+               { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4   },
+               { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5   },
+               { 0x0c, REG_HDMI_8960_PHY_PLL_SDM_CFG0      },
+               { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1      },
+               { 0x7d, REG_HDMI_8960_PHY_PLL_SDM_CFG2      },
+               { 0xbc, REG_HDMI_8960_PHY_PLL_SDM_CFG3      },
+               { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4      },
+               { 0, 0 } }
+       },
        { 65000000, {
                { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG    },
                { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
index c276624290afedb3f8de9fe9db2ed9271cab5ff4..b9a4ded6e400d089a92977f3fa69b0e19f7984a5 100644 (file)
@@ -8,9 +8,9 @@ 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:
-- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp5.xml            (  27229 bytes, from 2015-02-10 17:00:41)
+- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp5.xml            (  29312 bytes, from 2015-03-23 21:18:48)
 - /local/mnt2/workspace2/sviau/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2014-06-02 18:31:15)
-- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2015-01-23 16:20:19)
+- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2015-03-23 20:38:49)
 
 Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -37,11 +37,14 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
 
-enum mdp5_intf {
+enum mdp5_intf_type {
+       INTF_DISABLED = 0,
        INTF_DSI = 1,
        INTF_HDMI = 3,
        INTF_LCDC = 5,
        INTF_eDP = 9,
+       INTF_VIRTUAL = 100,
+       INTF_WB = 101,
 };
 
 enum mdp5_intfnum {
@@ -67,11 +70,11 @@ enum mdp5_pipe {
 
 enum mdp5_ctl_mode {
        MODE_NONE = 0,
-       MODE_ROT0 = 1,
-       MODE_ROT1 = 2,
-       MODE_WB0 = 3,
-       MODE_WB1 = 4,
-       MODE_WFD = 5,
+       MODE_WB_0_BLOCK = 1,
+       MODE_WB_1_BLOCK = 2,
+       MODE_WB_0_LINE = 3,
+       MODE_WB_1_LINE = 4,
+       MODE_WB_2_LINE = 5,
 };
 
 enum mdp5_pack_3d {
@@ -94,33 +97,6 @@ enum mdp5_pipe_bwc {
        BWC_Q_MED = 2,
 };
 
-enum mdp5_client_id {
-       CID_UNUSED = 0,
-       CID_VIG0_Y = 1,
-       CID_VIG0_CR = 2,
-       CID_VIG0_CB = 3,
-       CID_VIG1_Y = 4,
-       CID_VIG1_CR = 5,
-       CID_VIG1_CB = 6,
-       CID_VIG2_Y = 7,
-       CID_VIG2_CR = 8,
-       CID_VIG2_CB = 9,
-       CID_DMA0_Y = 10,
-       CID_DMA0_CR = 11,
-       CID_DMA0_CB = 12,
-       CID_DMA1_Y = 13,
-       CID_DMA1_CR = 14,
-       CID_DMA1_CB = 15,
-       CID_RGB0 = 16,
-       CID_RGB1 = 17,
-       CID_RGB2 = 18,
-       CID_VIG3_Y = 19,
-       CID_VIG3_CR = 20,
-       CID_VIG3_CB = 21,
-       CID_RGB3 = 22,
-       CID_MAX = 23,
-};
-
 enum mdp5_cursor_format {
        CURSOR_FMT_ARGB8888 = 0,
        CURSOR_FMT_ARGB1555 = 2,
@@ -144,30 +120,25 @@ enum mdp5_data_format {
        DATA_FORMAT_YUV = 1,
 };
 
-#define MDP5_IRQ_INTF0_WB_ROT_COMP                             0x00000001
-#define MDP5_IRQ_INTF1_WB_ROT_COMP                             0x00000002
-#define MDP5_IRQ_INTF2_WB_ROT_COMP                             0x00000004
-#define MDP5_IRQ_INTF3_WB_ROT_COMP                             0x00000008
-#define MDP5_IRQ_INTF0_WB_WFD                                  0x00000010
-#define MDP5_IRQ_INTF1_WB_WFD                                  0x00000020
-#define MDP5_IRQ_INTF2_WB_WFD                                  0x00000040
-#define MDP5_IRQ_INTF3_WB_WFD                                  0x00000080
-#define MDP5_IRQ_INTF0_PING_PONG_COMP                          0x00000100
-#define MDP5_IRQ_INTF1_PING_PONG_COMP                          0x00000200
-#define MDP5_IRQ_INTF2_PING_PONG_COMP                          0x00000400
-#define MDP5_IRQ_INTF3_PING_PONG_COMP                          0x00000800
-#define MDP5_IRQ_INTF0_PING_PONG_RD_PTR                                0x00001000
-#define MDP5_IRQ_INTF1_PING_PONG_RD_PTR                                0x00002000
-#define MDP5_IRQ_INTF2_PING_PONG_RD_PTR                                0x00004000
-#define MDP5_IRQ_INTF3_PING_PONG_RD_PTR                                0x00008000
-#define MDP5_IRQ_INTF0_PING_PONG_WR_PTR                                0x00010000
-#define MDP5_IRQ_INTF1_PING_PONG_WR_PTR                                0x00020000
-#define MDP5_IRQ_INTF2_PING_PONG_WR_PTR                                0x00040000
-#define MDP5_IRQ_INTF3_PING_PONG_WR_PTR                                0x00080000
-#define MDP5_IRQ_INTF0_PING_PONG_AUTO_REF                      0x00100000
-#define MDP5_IRQ_INTF1_PING_PONG_AUTO_REF                      0x00200000
-#define MDP5_IRQ_INTF2_PING_PONG_AUTO_REF                      0x00400000
-#define MDP5_IRQ_INTF3_PING_PONG_AUTO_REF                      0x00800000
+#define MDP5_IRQ_WB_0_DONE                                     0x00000001
+#define MDP5_IRQ_WB_1_DONE                                     0x00000002
+#define MDP5_IRQ_WB_2_DONE                                     0x00000010
+#define MDP5_IRQ_PING_PONG_0_DONE                              0x00000100
+#define MDP5_IRQ_PING_PONG_1_DONE                              0x00000200
+#define MDP5_IRQ_PING_PONG_2_DONE                              0x00000400
+#define MDP5_IRQ_PING_PONG_3_DONE                              0x00000800
+#define MDP5_IRQ_PING_PONG_0_RD_PTR                            0x00001000
+#define MDP5_IRQ_PING_PONG_1_RD_PTR                            0x00002000
+#define MDP5_IRQ_PING_PONG_2_RD_PTR                            0x00004000
+#define MDP5_IRQ_PING_PONG_3_RD_PTR                            0x00008000
+#define MDP5_IRQ_PING_PONG_0_WR_PTR                            0x00010000
+#define MDP5_IRQ_PING_PONG_1_WR_PTR                            0x00020000
+#define MDP5_IRQ_PING_PONG_2_WR_PTR                            0x00040000
+#define MDP5_IRQ_PING_PONG_3_WR_PTR                            0x00080000
+#define MDP5_IRQ_PING_PONG_0_AUTO_REF                          0x00100000
+#define MDP5_IRQ_PING_PONG_1_AUTO_REF                          0x00200000
+#define MDP5_IRQ_PING_PONG_2_AUTO_REF                          0x00400000
+#define MDP5_IRQ_PING_PONG_3_AUTO_REF                          0x00800000
 #define MDP5_IRQ_INTF0_UNDER_RUN                               0x01000000
 #define MDP5_IRQ_INTF0_VSYNC                                   0x02000000
 #define MDP5_IRQ_INTF1_UNDER_RUN                               0x04000000
@@ -176,136 +147,186 @@ enum mdp5_data_format {
 #define MDP5_IRQ_INTF2_VSYNC                                   0x20000000
 #define MDP5_IRQ_INTF3_UNDER_RUN                               0x40000000
 #define MDP5_IRQ_INTF3_VSYNC                                   0x80000000
-#define REG_MDP5_HW_VERSION                                    0x00000000
+#define REG_MDSS_HW_VERSION                                    0x00000000
+#define MDSS_HW_VERSION_STEP__MASK                             0x0000ffff
+#define MDSS_HW_VERSION_STEP__SHIFT                            0
+static inline uint32_t MDSS_HW_VERSION_STEP(uint32_t val)
+{
+       return ((val) << MDSS_HW_VERSION_STEP__SHIFT) & MDSS_HW_VERSION_STEP__MASK;
+}
+#define MDSS_HW_VERSION_MINOR__MASK                            0x0fff0000
+#define MDSS_HW_VERSION_MINOR__SHIFT                           16
+static inline uint32_t MDSS_HW_VERSION_MINOR(uint32_t val)
+{
+       return ((val) << MDSS_HW_VERSION_MINOR__SHIFT) & MDSS_HW_VERSION_MINOR__MASK;
+}
+#define MDSS_HW_VERSION_MAJOR__MASK                            0xf0000000
+#define MDSS_HW_VERSION_MAJOR__SHIFT                           28
+static inline uint32_t MDSS_HW_VERSION_MAJOR(uint32_t val)
+{
+       return ((val) << MDSS_HW_VERSION_MAJOR__SHIFT) & MDSS_HW_VERSION_MAJOR__MASK;
+}
+
+#define REG_MDSS_HW_INTR_STATUS                                        0x00000010
+#define MDSS_HW_INTR_STATUS_INTR_MDP                           0x00000001
+#define MDSS_HW_INTR_STATUS_INTR_DSI0                          0x00000010
+#define MDSS_HW_INTR_STATUS_INTR_DSI1                          0x00000020
+#define MDSS_HW_INTR_STATUS_INTR_HDMI                          0x00000100
+#define MDSS_HW_INTR_STATUS_INTR_EDP                           0x00001000
 
-#define REG_MDP5_HW_INTR_STATUS                                        0x00000010
-#define MDP5_HW_INTR_STATUS_INTR_MDP                           0x00000001
-#define MDP5_HW_INTR_STATUS_INTR_DSI0                          0x00000010
-#define MDP5_HW_INTR_STATUS_INTR_DSI1                          0x00000020
-#define MDP5_HW_INTR_STATUS_INTR_HDMI                          0x00000100
-#define MDP5_HW_INTR_STATUS_INTR_EDP                           0x00001000
+static inline uint32_t __offset_MDP(uint32_t idx)
+{
+       switch (idx) {
+               case 0: return (mdp5_cfg->mdp.base[0]);
+               default: return INVALID_IDX(idx);
+       }
+}
+static inline uint32_t REG_MDP5_MDP(uint32_t i0) { return 0x00000000 + __offset_MDP(i0); }
 
-#define REG_MDP5_MDP_VERSION                                   0x00000100
-#define MDP5_MDP_VERSION_MINOR__MASK                           0x00ff0000
-#define MDP5_MDP_VERSION_MINOR__SHIFT                          16
-static inline uint32_t MDP5_MDP_VERSION_MINOR(uint32_t val)
+static inline uint32_t REG_MDP5_MDP_HW_VERSION(uint32_t i0) { return 0x00000000 + __offset_MDP(i0); }
+#define MDP5_MDP_HW_VERSION_STEP__MASK                         0x0000ffff
+#define MDP5_MDP_HW_VERSION_STEP__SHIFT                                0
+static inline uint32_t MDP5_MDP_HW_VERSION_STEP(uint32_t val)
 {
-       return ((val) << MDP5_MDP_VERSION_MINOR__SHIFT) & MDP5_MDP_VERSION_MINOR__MASK;
+       return ((val) << MDP5_MDP_HW_VERSION_STEP__SHIFT) & MDP5_MDP_HW_VERSION_STEP__MASK;
 }
-#define MDP5_MDP_VERSION_MAJOR__MASK                           0xf0000000
-#define MDP5_MDP_VERSION_MAJOR__SHIFT                          28
-static inline uint32_t MDP5_MDP_VERSION_MAJOR(uint32_t val)
+#define MDP5_MDP_HW_VERSION_MINOR__MASK                                0x0fff0000
+#define MDP5_MDP_HW_VERSION_MINOR__SHIFT                       16
+static inline uint32_t MDP5_MDP_HW_VERSION_MINOR(uint32_t val)
 {
-       return ((val) << MDP5_MDP_VERSION_MAJOR__SHIFT) & MDP5_MDP_VERSION_MAJOR__MASK;
+       return ((val) << MDP5_MDP_HW_VERSION_MINOR__SHIFT) & MDP5_MDP_HW_VERSION_MINOR__MASK;
+}
+#define MDP5_MDP_HW_VERSION_MAJOR__MASK                                0xf0000000
+#define MDP5_MDP_HW_VERSION_MAJOR__SHIFT                       28
+static inline uint32_t MDP5_MDP_HW_VERSION_MAJOR(uint32_t val)
+{
+       return ((val) << MDP5_MDP_HW_VERSION_MAJOR__SHIFT) & MDP5_MDP_HW_VERSION_MAJOR__MASK;
 }
 
-#define REG_MDP5_DISP_INTF_SEL                                 0x00000104
-#define MDP5_DISP_INTF_SEL_INTF0__MASK                         0x000000ff
-#define MDP5_DISP_INTF_SEL_INTF0__SHIFT                                0
-static inline uint32_t MDP5_DISP_INTF_SEL_INTF0(enum mdp5_intf val)
+static inline uint32_t REG_MDP5_MDP_DISP_INTF_SEL(uint32_t i0) { return 0x00000004 + __offset_MDP(i0); }
+#define MDP5_MDP_DISP_INTF_SEL_INTF0__MASK                     0x000000ff
+#define MDP5_MDP_DISP_INTF_SEL_INTF0__SHIFT                    0
+static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF0(enum mdp5_intf_type val)
 {
-       return ((val) << MDP5_DISP_INTF_SEL_INTF0__SHIFT) & MDP5_DISP_INTF_SEL_INTF0__MASK;
+       return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF0__SHIFT) & MDP5_MDP_DISP_INTF_SEL_INTF0__MASK;
 }
-#define MDP5_DISP_INTF_SEL_INTF1__MASK                         0x0000ff00
-#define MDP5_DISP_INTF_SEL_INTF1__SHIFT                                8
-static inline uint32_t MDP5_DISP_INTF_SEL_INTF1(enum mdp5_intf val)
+#define MDP5_MDP_DISP_INTF_SEL_INTF1__MASK                     0x0000ff00
+#define MDP5_MDP_DISP_INTF_SEL_INTF1__SHIFT                    8
+static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF1(enum mdp5_intf_type val)
 {
-       return ((val) << MDP5_DISP_INTF_SEL_INTF1__SHIFT) & MDP5_DISP_INTF_SEL_INTF1__MASK;
+       return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF1__SHIFT) & MDP5_MDP_DISP_INTF_SEL_INTF1__MASK;
 }
-#define MDP5_DISP_INTF_SEL_INTF2__MASK                         0x00ff0000
-#define MDP5_DISP_INTF_SEL_INTF2__SHIFT                                16
-static inline uint32_t MDP5_DISP_INTF_SEL_INTF2(enum mdp5_intf val)
+#define MDP5_MDP_DISP_INTF_SEL_INTF2__MASK                     0x00ff0000
+#define MDP5_MDP_DISP_INTF_SEL_INTF2__SHIFT                    16
+static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF2(enum mdp5_intf_type val)
 {
-       return ((val) << MDP5_DISP_INTF_SEL_INTF2__SHIFT) & MDP5_DISP_INTF_SEL_INTF2__MASK;
+       return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF2__SHIFT) & MDP5_MDP_DISP_INTF_SEL_INTF2__MASK;
 }
-#define MDP5_DISP_INTF_SEL_INTF3__MASK                         0xff000000
-#define MDP5_DISP_INTF_SEL_INTF3__SHIFT                                24
-static inline uint32_t MDP5_DISP_INTF_SEL_INTF3(enum mdp5_intf val)
+#define MDP5_MDP_DISP_INTF_SEL_INTF3__MASK                     0xff000000
+#define MDP5_MDP_DISP_INTF_SEL_INTF3__SHIFT                    24
+static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF3(enum mdp5_intf_type val)
 {
-       return ((val) << MDP5_DISP_INTF_SEL_INTF3__SHIFT) & MDP5_DISP_INTF_SEL_INTF3__MASK;
+       return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF3__SHIFT) & MDP5_MDP_DISP_INTF_SEL_INTF3__MASK;
 }
 
-#define REG_MDP5_INTR_EN                                       0x00000110
+static inline uint32_t REG_MDP5_MDP_INTR_EN(uint32_t i0) { return 0x00000010 + __offset_MDP(i0); }
 
-#define REG_MDP5_INTR_STATUS                                   0x00000114
+static inline uint32_t REG_MDP5_MDP_INTR_STATUS(uint32_t i0) { return 0x00000014 + __offset_MDP(i0); }
 
-#define REG_MDP5_INTR_CLEAR                                    0x00000118
+static inline uint32_t REG_MDP5_MDP_INTR_CLEAR(uint32_t i0) { return 0x00000018 + __offset_MDP(i0); }
 
-#define REG_MDP5_HIST_INTR_EN                                  0x0000011c
+static inline uint32_t REG_MDP5_MDP_HIST_INTR_EN(uint32_t i0) { return 0x0000001c + __offset_MDP(i0); }
 
-#define REG_MDP5_HIST_INTR_STATUS                              0x00000120
+static inline uint32_t REG_MDP5_MDP_HIST_INTR_STATUS(uint32_t i0) { return 0x00000020 + __offset_MDP(i0); }
 
-#define REG_MDP5_HIST_INTR_CLEAR                               0x00000124
+static inline uint32_t REG_MDP5_MDP_HIST_INTR_CLEAR(uint32_t i0) { return 0x00000024 + __offset_MDP(i0); }
 
-static inline uint32_t REG_MDP5_SMP_ALLOC_W(uint32_t i0) { return 0x00000180 + 0x4*i0; }
+static inline uint32_t REG_MDP5_MDP_SPARE_0(uint32_t i0) { return 0x00000028 + __offset_MDP(i0); }
+#define MDP5_MDP_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN             0x00000001
 
-static inline uint32_t REG_MDP5_SMP_ALLOC_W_REG(uint32_t i0) { return 0x00000180 + 0x4*i0; }
-#define MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK                     0x000000ff
-#define MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT                    0
-static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT0(enum mdp5_client_id val)
+static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_W(uint32_t i0, uint32_t i1) { return 0x00000080 + __offset_MDP(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_W_REG(uint32_t i0, uint32_t i1) { return 0x00000080 + __offset_MDP(i0) + 0x4*i1; }
+#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__MASK                 0x000000ff
+#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__SHIFT                        0
+static inline uint32_t MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0(uint32_t val)
 {
-       return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK;
+       return ((val) << MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__SHIFT) & MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__MASK;
 }
-#define MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK                     0x0000ff00
-#define MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT                    8
-static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT1(enum mdp5_client_id val)
+#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__MASK                 0x0000ff00
+#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__SHIFT                        8
+static inline uint32_t MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1(uint32_t val)
 {
-       return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK;
+       return ((val) << MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__SHIFT) & MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__MASK;
 }
-#define MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK                     0x00ff0000
-#define MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT                    16
-static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT2(enum mdp5_client_id val)
+#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__MASK                 0x00ff0000
+#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__SHIFT                        16
+static inline uint32_t MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2(uint32_t val)
 {
-       return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK;
+       return ((val) << MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__SHIFT) & MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__MASK;
 }
 
-static inline uint32_t REG_MDP5_SMP_ALLOC_R(uint32_t i0) { return 0x00000230 + 0x4*i0; }
+static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_R(uint32_t i0, uint32_t i1) { return 0x00000130 + __offset_MDP(i0) + 0x4*i1; }
 
-static inline uint32_t REG_MDP5_SMP_ALLOC_R_REG(uint32_t i0) { return 0x00000230 + 0x4*i0; }
-#define MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK                     0x000000ff
-#define MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT                    0
-static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT0(enum mdp5_client_id val)
+static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_R_REG(uint32_t i0, uint32_t i1) { return 0x00000130 + __offset_MDP(i0) + 0x4*i1; }
+#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__MASK                 0x000000ff
+#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__SHIFT                        0
+static inline uint32_t MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0(uint32_t val)
 {
-       return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK;
+       return ((val) << MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__SHIFT) & MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__MASK;
 }
-#define MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK                     0x0000ff00
-#define MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT                    8
-static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT1(enum mdp5_client_id val)
+#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__MASK                 0x0000ff00
+#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__SHIFT                        8
+static inline uint32_t MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1(uint32_t val)
 {
-       return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK;
+       return ((val) << MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__SHIFT) & MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__MASK;
 }
-#define MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK                     0x00ff0000
-#define MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT                    16
-static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT2(enum mdp5_client_id val)
+#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__MASK                 0x00ff0000
+#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__SHIFT                        16
+static inline uint32_t MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2(uint32_t val)
 {
-       return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK;
+       return ((val) << MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__SHIFT) & MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__MASK;
 }
 
 static inline uint32_t __offset_IGC(enum mdp5_igc_type idx)
 {
        switch (idx) {
-               case IGC_VIG: return 0x00000300;
-               case IGC_RGB: return 0x00000310;
-               case IGC_DMA: return 0x00000320;
-               case IGC_DSPP: return 0x00000400;
+               case IGC_VIG: return 0x00000200;
+               case IGC_RGB: return 0x00000210;
+               case IGC_DMA: return 0x00000220;
+               case IGC_DSPP: return 0x00000300;
                default: return INVALID_IDX(idx);
        }
 }
-static inline uint32_t REG_MDP5_IGC(enum mdp5_igc_type i0) { return 0x00000000 + __offset_IGC(i0); }
+static inline uint32_t REG_MDP5_MDP_IGC(uint32_t i0, enum mdp5_igc_type i1) { return 0x00000000 + __offset_MDP(i0) + __offset_IGC(i1); }
 
-static inline uint32_t REG_MDP5_IGC_LUT(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; }
+static inline uint32_t REG_MDP5_MDP_IGC_LUT(uint32_t i0, enum mdp5_igc_type i1, uint32_t i2) { return 0x00000000 + __offset_MDP(i0) + __offset_IGC(i1) + 0x4*i2; }
 
-static inline uint32_t REG_MDP5_IGC_LUT_REG(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; }
-#define MDP5_IGC_LUT_REG_VAL__MASK                             0x00000fff
-#define MDP5_IGC_LUT_REG_VAL__SHIFT                            0
-static inline uint32_t MDP5_IGC_LUT_REG_VAL(uint32_t val)
+static inline uint32_t REG_MDP5_MDP_IGC_LUT_REG(uint32_t i0, enum mdp5_igc_type i1, uint32_t i2) { return 0x00000000 + __offset_MDP(i0) + __offset_IGC(i1) + 0x4*i2; }
+#define MDP5_MDP_IGC_LUT_REG_VAL__MASK                         0x00000fff
+#define MDP5_MDP_IGC_LUT_REG_VAL__SHIFT                                0
+static inline uint32_t MDP5_MDP_IGC_LUT_REG_VAL(uint32_t val)
 {
-       return ((val) << MDP5_IGC_LUT_REG_VAL__SHIFT) & MDP5_IGC_LUT_REG_VAL__MASK;
+       return ((val) << MDP5_MDP_IGC_LUT_REG_VAL__SHIFT) & MDP5_MDP_IGC_LUT_REG_VAL__MASK;
 }
-#define MDP5_IGC_LUT_REG_INDEX_UPDATE                          0x02000000
-#define MDP5_IGC_LUT_REG_DISABLE_PIPE_0                                0x10000000
-#define MDP5_IGC_LUT_REG_DISABLE_PIPE_1                                0x20000000
-#define MDP5_IGC_LUT_REG_DISABLE_PIPE_2                                0x40000000
+#define MDP5_MDP_IGC_LUT_REG_INDEX_UPDATE                      0x02000000
+#define MDP5_MDP_IGC_LUT_REG_DISABLE_PIPE_0                    0x10000000
+#define MDP5_MDP_IGC_LUT_REG_DISABLE_PIPE_1                    0x20000000
+#define MDP5_MDP_IGC_LUT_REG_DISABLE_PIPE_2                    0x40000000
+
+#define REG_MDP5_SPLIT_DPL_EN                                  0x000003f4
+
+#define REG_MDP5_SPLIT_DPL_UPPER                               0x000003f8
+#define MDP5_SPLIT_DPL_UPPER_SMART_PANEL                       0x00000002
+#define MDP5_SPLIT_DPL_UPPER_SMART_PANEL_FREE_RUN              0x00000004
+#define MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX                  0x00000010
+#define MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX                  0x00000100
+
+#define REG_MDP5_SPLIT_DPL_LOWER                               0x000004f0
+#define MDP5_SPLIT_DPL_LOWER_SMART_PANEL                       0x00000002
+#define MDP5_SPLIT_DPL_LOWER_SMART_PANEL_FREE_RUN              0x00000004
+#define MDP5_SPLIT_DPL_LOWER_INTF1_TG_SYNC                     0x00000010
+#define MDP5_SPLIT_DPL_LOWER_INTF2_TG_SYNC                     0x00000100
 
 static inline uint32_t __offset_CTL(uint32_t idx)
 {
@@ -437,11 +458,19 @@ static inline uint32_t REG_MDP5_CTL_FLUSH(uint32_t i0) { return 0x00000018 + __o
 #define MDP5_CTL_FLUSH_DSPP0                                   0x00002000
 #define MDP5_CTL_FLUSH_DSPP1                                   0x00004000
 #define MDP5_CTL_FLUSH_DSPP2                                   0x00008000
+#define MDP5_CTL_FLUSH_WB                                      0x00010000
 #define MDP5_CTL_FLUSH_CTL                                     0x00020000
 #define MDP5_CTL_FLUSH_VIG3                                    0x00040000
 #define MDP5_CTL_FLUSH_RGB3                                    0x00080000
 #define MDP5_CTL_FLUSH_LM5                                     0x00100000
 #define MDP5_CTL_FLUSH_DSPP3                                   0x00200000
+#define MDP5_CTL_FLUSH_CURSOR_0                                        0x00400000
+#define MDP5_CTL_FLUSH_CURSOR_1                                        0x00800000
+#define MDP5_CTL_FLUSH_CHROMADOWN_0                            0x04000000
+#define MDP5_CTL_FLUSH_TIMING_3                                        0x10000000
+#define MDP5_CTL_FLUSH_TIMING_2                                        0x20000000
+#define MDP5_CTL_FLUSH_TIMING_1                                        0x40000000
+#define MDP5_CTL_FLUSH_TIMING_0                                        0x80000000
 
 static inline uint32_t REG_MDP5_CTL_START(uint32_t i0) { return 0x0000001c + __offset_CTL(i0); }
 
@@ -1117,6 +1146,94 @@ static inline uint32_t REG_MDP5_DSPP_GAMUT_BASE(uint32_t i0) { return 0x000002dc
 
 static inline uint32_t REG_MDP5_DSPP_GC_BASE(uint32_t i0) { return 0x000002b0 + __offset_DSPP(i0); }
 
+static inline uint32_t __offset_PP(uint32_t idx)
+{
+       switch (idx) {
+               case 0: return (mdp5_cfg->pp.base[0]);
+               case 1: return (mdp5_cfg->pp.base[1]);
+               case 2: return (mdp5_cfg->pp.base[2]);
+               case 3: return (mdp5_cfg->pp.base[3]);
+               default: return INVALID_IDX(idx);
+       }
+}
+static inline uint32_t REG_MDP5_PP(uint32_t i0) { return 0x00000000 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_TEAR_CHECK_EN(uint32_t i0) { return 0x00000000 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_SYNC_CONFIG_VSYNC(uint32_t i0) { return 0x00000004 + __offset_PP(i0); }
+#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__MASK                  0x0007ffff
+#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__SHIFT                 0
+static inline uint32_t MDP5_PP_SYNC_CONFIG_VSYNC_COUNT(uint32_t val)
+{
+       return ((val) << MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__SHIFT) & MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__MASK;
+}
+#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNTER_EN                   0x00080000
+#define MDP5_PP_SYNC_CONFIG_VSYNC_IN_EN                                0x00100000
+
+static inline uint32_t REG_MDP5_PP_SYNC_CONFIG_HEIGHT(uint32_t i0) { return 0x00000008 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_SYNC_WRCOUNT(uint32_t i0) { return 0x0000000c + __offset_PP(i0); }
+#define MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__MASK                  0x0000ffff
+#define MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__SHIFT                 0
+static inline uint32_t MDP5_PP_SYNC_WRCOUNT_LINE_COUNT(uint32_t val)
+{
+       return ((val) << MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__SHIFT) & MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__MASK;
+}
+#define MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__MASK                 0xffff0000
+#define MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__SHIFT                        16
+static inline uint32_t MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT(uint32_t val)
+{
+       return ((val) << MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__SHIFT) & MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__MASK;
+}
+
+static inline uint32_t REG_MDP5_PP_VSYNC_INIT_VAL(uint32_t i0) { return 0x00000010 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_INT_COUNT_VAL(uint32_t i0) { return 0x00000014 + __offset_PP(i0); }
+#define MDP5_PP_INT_COUNT_VAL_LINE_COUNT__MASK                 0x0000ffff
+#define MDP5_PP_INT_COUNT_VAL_LINE_COUNT__SHIFT                        0
+static inline uint32_t MDP5_PP_INT_COUNT_VAL_LINE_COUNT(uint32_t val)
+{
+       return ((val) << MDP5_PP_INT_COUNT_VAL_LINE_COUNT__SHIFT) & MDP5_PP_INT_COUNT_VAL_LINE_COUNT__MASK;
+}
+#define MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__MASK                        0xffff0000
+#define MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__SHIFT               16
+static inline uint32_t MDP5_PP_INT_COUNT_VAL_FRAME_COUNT(uint32_t val)
+{
+       return ((val) << MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__SHIFT) & MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__MASK;
+}
+
+static inline uint32_t REG_MDP5_PP_SYNC_THRESH(uint32_t i0) { return 0x00000018 + __offset_PP(i0); }
+#define MDP5_PP_SYNC_THRESH_START__MASK                                0x0000ffff
+#define MDP5_PP_SYNC_THRESH_START__SHIFT                       0
+static inline uint32_t MDP5_PP_SYNC_THRESH_START(uint32_t val)
+{
+       return ((val) << MDP5_PP_SYNC_THRESH_START__SHIFT) & MDP5_PP_SYNC_THRESH_START__MASK;
+}
+#define MDP5_PP_SYNC_THRESH_CONTINUE__MASK                     0xffff0000
+#define MDP5_PP_SYNC_THRESH_CONTINUE__SHIFT                    16
+static inline uint32_t MDP5_PP_SYNC_THRESH_CONTINUE(uint32_t val)
+{
+       return ((val) << MDP5_PP_SYNC_THRESH_CONTINUE__SHIFT) & MDP5_PP_SYNC_THRESH_CONTINUE__MASK;
+}
+
+static inline uint32_t REG_MDP5_PP_START_POS(uint32_t i0) { return 0x0000001c + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_RD_PTR_IRQ(uint32_t i0) { return 0x00000020 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_WR_PTR_IRQ(uint32_t i0) { return 0x00000024 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_OUT_LINE_COUNT(uint32_t i0) { return 0x00000028 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_PP_LINE_COUNT(uint32_t i0) { return 0x0000002c + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_AUTOREFRESH_CONFIG(uint32_t i0) { return 0x00000030 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_FBC_MODE(uint32_t i0) { return 0x00000034 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_FBC_BUDGET_CTL(uint32_t i0) { return 0x00000038 + __offset_PP(i0); }
+
+static inline uint32_t REG_MDP5_PP_FBC_LOSSY_MODE(uint32_t i0) { return 0x0000003c + __offset_PP(i0); }
+
 static inline uint32_t __offset_INTF(uint32_t idx)
 {
        switch (idx) {
index b0a44310cf2a057275840171cf2ee23926c84dc4..e001e6b2296a2ebd5cf602fbf0e3ba89f49ecf0d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015 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
@@ -24,13 +24,23 @@ const struct mdp5_cfg_hw *mdp5_cfg = NULL;
 
 const struct mdp5_cfg_hw msm8x74_config = {
        .name = "msm8x74",
+       .mdp = {
+               .count = 1,
+               .base = { 0x00100 },
+       },
        .smp = {
                .mmb_count = 22,
                .mmb_size = 4096,
+               .clients = {
+                       [SSPP_VIG0] =  1, [SSPP_VIG1] =  4, [SSPP_VIG2] =  7,
+                       [SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
+                       [SSPP_RGB0] = 16, [SSPP_RGB1] = 17, [SSPP_RGB2] = 18,
+               },
        },
        .ctl = {
                .count = 5,
                .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 },
+               .flush_hw_mask = 0x0003ffff,
        },
        .pipe_vig = {
                .count = 3,
@@ -57,27 +67,49 @@ const struct mdp5_cfg_hw msm8x74_config = {
                .count = 2,
                .base = { 0x13100, 0x13300 }, /* NOTE: no ad in v1.0 */
        },
+       .pp = {
+               .count = 3,
+               .base = { 0x12d00, 0x12e00, 0x12f00 },
+       },
        .intf = {
                .count = 4,
                .base = { 0x12500, 0x12700, 0x12900, 0x12b00 },
        },
+       .intfs = {
+               [0] = INTF_eDP,
+               [1] = INTF_DSI,
+               [2] = INTF_DSI,
+               [3] = INTF_HDMI,
+       },
        .max_clk = 200000000,
 };
 
 const struct mdp5_cfg_hw apq8084_config = {
        .name = "apq8084",
+       .mdp = {
+               .count = 1,
+               .base = { 0x00100 },
+       },
        .smp = {
                .mmb_count = 44,
                .mmb_size = 8192,
+               .clients = {
+                       [SSPP_VIG0] =  1, [SSPP_VIG1] =  4,
+                       [SSPP_VIG2] =  7, [SSPP_VIG3] = 19,
+                       [SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
+                       [SSPP_RGB0] = 16, [SSPP_RGB1] = 17,
+                       [SSPP_RGB2] = 18, [SSPP_RGB3] = 22,
+               },
                .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,
+               .reserved = {
+                       /* Two SMP blocks are statically tied to RGB pipes: */
+                       [16] = 2, [17] = 2, [18] = 2, [22] = 2,
+               },
        },
        .ctl = {
                .count = 5,
                .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 },
+               .flush_hw_mask = 0x003fffff,
        },
        .pipe_vig = {
                .count = 4,
@@ -105,10 +137,69 @@ const struct mdp5_cfg_hw apq8084_config = {
                .count = 3,
                .base = { 0x13500, 0x13700, 0x13900 },
        },
+       .pp = {
+               .count = 4,
+               .base = { 0x12f00, 0x13000, 0x13100, 0x13200 },
+       },
        .intf = {
                .count = 5,
                .base = { 0x12500, 0x12700, 0x12900, 0x12b00, 0x12d00 },
        },
+       .intfs = {
+               [0] = INTF_eDP,
+               [1] = INTF_DSI,
+               [2] = INTF_DSI,
+               [3] = INTF_HDMI,
+       },
+       .max_clk = 320000000,
+};
+
+const struct mdp5_cfg_hw msm8x16_config = {
+       .name = "msm8x16",
+       .mdp = {
+               .count = 1,
+               .base = { 0x01000 },
+       },
+       .smp = {
+               .mmb_count = 8,
+               .mmb_size = 8192,
+               .clients = {
+                       [SSPP_VIG0] = 1, [SSPP_DMA0] = 4,
+                       [SSPP_RGB0] = 7, [SSPP_RGB1] = 8,
+               },
+       },
+       .ctl = {
+               .count = 5,
+               .base = { 0x02000, 0x02200, 0x02400, 0x02600, 0x02800 },
+               .flush_hw_mask = 0x4003ffff,
+       },
+       .pipe_vig = {
+               .count = 1,
+               .base = { 0x05000 },
+       },
+       .pipe_rgb = {
+               .count = 2,
+               .base = { 0x15000, 0x17000 },
+       },
+       .pipe_dma = {
+               .count = 1,
+               .base = { 0x25000 },
+       },
+       .lm = {
+               .count = 2, /* LM0 and LM3 */
+               .base = { 0x45000, 0x48000 },
+               .nb_stages = 5,
+       },
+       .dspp = {
+               .count = 1,
+               .base = { 0x55000 },
+
+       },
+       .intf = {
+               .count = 1, /* INTF_1 */
+               .base = { 0x6B800 },
+       },
+       /* TODO enable .intfs[] with [1] = INTF_DSI, once DSI is implemented */
        .max_clk = 320000000,
 };
 
@@ -116,6 +207,7 @@ 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 } },
+       { .revision = 6, .config = { .hw = &msm8x16_config } },
 };
 
 
index dba4d52cceebaeec609b95cdbcf27af495d5a545..3a551b0892d847e50fb48054bfb6c409887fd40b 100644 (file)
@@ -44,26 +44,38 @@ struct mdp5_lm_block {
        uint32_t nb_stages;             /* number of stages per blender */
 };
 
+struct mdp5_ctl_block {
+       MDP5_SUB_BLOCK_DEFINITION;
+       uint32_t flush_hw_mask;         /* FLUSH register's hardware mask */
+};
+
 struct mdp5_smp_block {
        int mmb_count;                  /* number of SMP MMBs */
        int mmb_size;                   /* MMB: size in bytes */
+       uint32_t clients[MAX_CLIENTS];  /* SMP port allocation /pipe */
        mdp5_smp_state_t reserved_state;/* SMP MMBs statically allocated */
        int reserved[MAX_CLIENTS];      /* # of MMBs allocated per client */
 };
 
+#define MDP5_INTF_NUM_MAX      5
+
 struct mdp5_cfg_hw {
        char  *name;
 
+       struct mdp5_sub_block mdp;
        struct mdp5_smp_block smp;
-       struct mdp5_sub_block ctl;
+       struct mdp5_ctl_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 pp;
        struct mdp5_sub_block intf;
 
+       u32 intfs[MDP5_INTF_NUM_MAX]; /* array of enum mdp5_intf_type */
+
        uint32_t max_clk;
 };
 
@@ -84,6 +96,10 @@ const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_hn
 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);
 
+#define mdp5_cfg_intf_is_virtual(intf_type) ({ \
+       typeof(intf_type) __val = (intf_type);  \
+       (__val) >= INTF_VIRTUAL ? true : false; })
+
 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);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c
new file mode 100644 (file)
index 0000000..e4e8956
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2015, 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 "drm_crtc.h"
+#include "drm_crtc_helper.h"
+
+struct mdp5_cmd_encoder {
+       struct drm_encoder base;
+       struct mdp5_interface intf;
+       bool enabled;
+       uint32_t bsc;
+};
+#define to_mdp5_cmd_encoder(x) container_of(x, struct mdp5_cmd_encoder, base)
+
+static struct mdp5_kms *get_kms(struct drm_encoder *encoder)
+{
+       struct msm_drm_private *priv = encoder->dev->dev_private;
+       return to_mdp5_kms(to_mdp_kms(priv->kms));
+}
+
+#ifdef CONFIG_MSM_BUS_SCALING
+#include <mach/board.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val)           \
+       {                                               \
+               .src = MSM_BUS_MASTER_MDP_PORT0,        \
+               .dst = MSM_BUS_SLAVE_EBI_CH0,           \
+               .ab = (ab_val),                         \
+               .ib = (ib_val),                         \
+       }
+
+static struct msm_bus_vectors mdp_bus_vectors[] = {
+       MDP_BUS_VECTOR_ENTRY(0, 0),
+       MDP_BUS_VECTOR_ENTRY(2000000000, 2000000000),
+};
+static struct msm_bus_paths mdp_bus_usecases[] = { {
+               .num_paths = 1,
+               .vectors = &mdp_bus_vectors[0],
+}, {
+               .num_paths = 1,
+               .vectors = &mdp_bus_vectors[1],
+} };
+static struct msm_bus_scale_pdata mdp_bus_scale_table = {
+       .usecase = mdp_bus_usecases,
+       .num_usecases = ARRAY_SIZE(mdp_bus_usecases),
+       .name = "mdss_mdp",
+};
+
+static void bs_init(struct mdp5_cmd_encoder *mdp5_cmd_enc)
+{
+       mdp5_cmd_enc->bsc = msm_bus_scale_register_client(
+                       &mdp_bus_scale_table);
+       DBG("bus scale client: %08x", mdp5_cmd_enc->bsc);
+}
+
+static void bs_fini(struct mdp5_cmd_encoder *mdp5_cmd_enc)
+{
+       if (mdp5_cmd_enc->bsc) {
+               msm_bus_scale_unregister_client(mdp5_cmd_enc->bsc);
+               mdp5_cmd_enc->bsc = 0;
+       }
+}
+
+static void bs_set(struct mdp5_cmd_encoder *mdp5_cmd_enc, int idx)
+{
+       if (mdp5_cmd_enc->bsc) {
+               DBG("set bus scaling: %d", idx);
+               /* HACK: scaling down, and then immediately back up
+                * seems to leave things broken (underflow).. so
+                * never disable:
+                */
+               idx = 1;
+               msm_bus_scale_client_update_request(mdp5_cmd_enc->bsc, idx);
+       }
+}
+#else
+static void bs_init(struct mdp5_cmd_encoder *mdp5_cmd_enc) {}
+static void bs_fini(struct mdp5_cmd_encoder *mdp5_cmd_enc) {}
+static void bs_set(struct mdp5_cmd_encoder *mdp5_cmd_enc, int idx) {}
+#endif
+
+#define VSYNC_CLK_RATE 19200000
+static int pingpong_tearcheck_setup(struct drm_encoder *encoder,
+                                       struct drm_display_mode *mode)
+{
+       struct mdp5_kms *mdp5_kms = get_kms(encoder);
+       struct device *dev = encoder->dev->dev;
+       u32 total_lines_x100, vclks_line, cfg;
+       long vsync_clk_speed;
+       int pp_id = GET_PING_PONG_ID(mdp5_crtc_get_lm(encoder->crtc));
+
+       if (IS_ERR_OR_NULL(mdp5_kms->vsync_clk)) {
+               dev_err(dev, "vsync_clk is not initialized\n");
+               return -EINVAL;
+       }
+
+       total_lines_x100 = mode->vtotal * mode->vrefresh;
+       if (!total_lines_x100) {
+               dev_err(dev, "%s: vtotal(%d) or vrefresh(%d) is 0\n",
+                               __func__, mode->vtotal, mode->vrefresh);
+               return -EINVAL;
+       }
+
+       vsync_clk_speed = clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE);
+       if (vsync_clk_speed <= 0) {
+               dev_err(dev, "vsync_clk round rate failed %ld\n",
+                                                       vsync_clk_speed);
+               return -EINVAL;
+       }
+       vclks_line = vsync_clk_speed * 100 / total_lines_x100;
+
+       cfg = MDP5_PP_SYNC_CONFIG_VSYNC_COUNTER_EN
+               | MDP5_PP_SYNC_CONFIG_VSYNC_IN_EN;
+       cfg |= MDP5_PP_SYNC_CONFIG_VSYNC_COUNT(vclks_line);
+
+       mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_CONFIG_VSYNC(pp_id), cfg);
+       mdp5_write(mdp5_kms,
+               REG_MDP5_PP_SYNC_CONFIG_HEIGHT(pp_id), 0xfff0);
+       mdp5_write(mdp5_kms,
+               REG_MDP5_PP_VSYNC_INIT_VAL(pp_id), mode->vdisplay);
+       mdp5_write(mdp5_kms, REG_MDP5_PP_RD_PTR_IRQ(pp_id), mode->vdisplay + 1);
+       mdp5_write(mdp5_kms, REG_MDP5_PP_START_POS(pp_id), mode->vdisplay);
+       mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_THRESH(pp_id),
+                       MDP5_PP_SYNC_THRESH_START(4) |
+                       MDP5_PP_SYNC_THRESH_CONTINUE(4));
+
+       return 0;
+}
+
+static int pingpong_tearcheck_enable(struct drm_encoder *encoder)
+{
+       struct mdp5_kms *mdp5_kms = get_kms(encoder);
+       int pp_id = GET_PING_PONG_ID(mdp5_crtc_get_lm(encoder->crtc));
+       int ret;
+
+       ret = clk_set_rate(mdp5_kms->vsync_clk,
+               clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE));
+       if (ret) {
+               dev_err(encoder->dev->dev,
+                       "vsync_clk clk_set_rate failed, %d\n", ret);
+               return ret;
+       }
+       ret = clk_prepare_enable(mdp5_kms->vsync_clk);
+       if (ret) {
+               dev_err(encoder->dev->dev,
+                       "vsync_clk clk_prepare_enable failed, %d\n", ret);
+               return ret;
+       }
+
+       mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 1);
+
+       return 0;
+}
+
+static void pingpong_tearcheck_disable(struct drm_encoder *encoder)
+{
+       struct mdp5_kms *mdp5_kms = get_kms(encoder);
+       int pp_id = GET_PING_PONG_ID(mdp5_crtc_get_lm(encoder->crtc));
+
+       mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 0);
+       clk_disable_unprepare(mdp5_kms->vsync_clk);
+}
+
+static void mdp5_cmd_encoder_destroy(struct drm_encoder *encoder)
+{
+       struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
+       bs_fini(mdp5_cmd_enc);
+       drm_encoder_cleanup(encoder);
+       kfree(mdp5_cmd_enc);
+}
+
+static const struct drm_encoder_funcs mdp5_cmd_encoder_funcs = {
+       .destroy = mdp5_cmd_encoder_destroy,
+};
+
+static bool mdp5_cmd_encoder_mode_fixup(struct drm_encoder *encoder,
+               const struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
+
+       mode = adjusted_mode;
+
+       DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
+                       mode->base.id, mode->name,
+                       mode->vrefresh, mode->clock,
+                       mode->hdisplay, mode->hsync_start,
+                       mode->hsync_end, mode->htotal,
+                       mode->vdisplay, mode->vsync_start,
+                       mode->vsync_end, mode->vtotal,
+                       mode->type, mode->flags);
+       pingpong_tearcheck_setup(encoder, mode);
+       mdp5_crtc_set_intf(encoder->crtc, &mdp5_cmd_enc->intf);
+}
+
+static void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
+{
+       struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
+       struct mdp5_kms *mdp5_kms = get_kms(encoder);
+       struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
+       struct mdp5_interface *intf = &mdp5_cmd_enc->intf;
+       int lm = mdp5_crtc_get_lm(encoder->crtc);
+
+       if (WARN_ON(!mdp5_cmd_enc->enabled))
+               return;
+
+       /* Wait for the last frame done */
+       mdp_irq_wait(&mdp5_kms->base, lm2ppdone(lm));
+       pingpong_tearcheck_disable(encoder);
+
+       mdp5_ctl_set_encoder_state(ctl, false);
+       mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf));
+
+       bs_set(mdp5_cmd_enc, 0);
+
+       mdp5_cmd_enc->enabled = false;
+}
+
+static void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
+{
+       struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
+       struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
+       struct mdp5_interface *intf = &mdp5_cmd_enc->intf;
+
+       if (WARN_ON(mdp5_cmd_enc->enabled))
+               return;
+
+       bs_set(mdp5_cmd_enc, 1);
+       if (pingpong_tearcheck_enable(encoder))
+               return;
+
+       mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf));
+
+       mdp5_ctl_set_encoder_state(ctl, true);
+
+       mdp5_cmd_enc->enabled = true;
+}
+
+static const struct drm_encoder_helper_funcs mdp5_cmd_encoder_helper_funcs = {
+       .mode_fixup = mdp5_cmd_encoder_mode_fixup,
+       .mode_set = mdp5_cmd_encoder_mode_set,
+       .disable = mdp5_cmd_encoder_disable,
+       .enable = mdp5_cmd_encoder_enable,
+};
+
+int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
+                                       struct drm_encoder *slave_encoder)
+{
+       struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
+       struct mdp5_kms *mdp5_kms;
+       int intf_num;
+       u32 data = 0;
+
+       if (!encoder || !slave_encoder)
+               return -EINVAL;
+
+       mdp5_kms = get_kms(encoder);
+       intf_num = mdp5_cmd_enc->intf.num;
+
+       /* Switch slave encoder's trigger MUX, to use the master's
+        * start signal for the slave encoder
+        */
+       if (intf_num == 1)
+               data |= MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX;
+       else if (intf_num == 2)
+               data |= MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX;
+       else
+               return -EINVAL;
+
+       /* Smart Panel, Sync mode */
+       data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL;
+
+       /* Make sure clocks are on when connectors calling this function. */
+       mdp5_enable(mdp5_kms);
+       mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, data);
+
+       mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER,
+                       MDP5_SPLIT_DPL_LOWER_SMART_PANEL);
+       mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1);
+       mdp5_disable(mdp5_kms);
+
+       return 0;
+}
+
+/* initialize command mode encoder */
+struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
+                               struct mdp5_interface *intf)
+{
+       struct drm_encoder *encoder = NULL;
+       struct mdp5_cmd_encoder *mdp5_cmd_enc;
+       int ret;
+
+       if (WARN_ON((intf->type != INTF_DSI) &&
+               (intf->mode != MDP5_INTF_DSI_MODE_COMMAND))) {
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       mdp5_cmd_enc = kzalloc(sizeof(*mdp5_cmd_enc), GFP_KERNEL);
+       if (!mdp5_cmd_enc) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       memcpy(&mdp5_cmd_enc->intf, intf, sizeof(mdp5_cmd_enc->intf));
+       encoder = &mdp5_cmd_enc->base;
+
+       drm_encoder_init(dev, encoder, &mdp5_cmd_encoder_funcs,
+                       DRM_MODE_ENCODER_DSI);
+
+       drm_encoder_helper_add(encoder, &mdp5_cmd_encoder_helper_funcs);
+
+       bs_init(mdp5_cmd_enc);
+
+       return encoder;
+
+fail:
+       if (encoder)
+               mdp5_cmd_encoder_destroy(encoder);
+
+       return ERR_PTR(ret);
+}
+
index 2f2863cf8b45f21e692e3e50f09c88275d83da63..c1530772187dbd36bf672723af074f0af9a44c5d 100644 (file)
@@ -82,8 +82,6 @@ static void request_pending(struct drm_crtc *crtc, uint32_t pending)
        mdp_irq_register(&get_kms(crtc)->base, &mdp5_crtc->vblank);
 }
 
-#define mdp5_lm_get_flush(lm)  mdp_ctl_flush_mask_lm(lm)
-
 static void crtc_flush(struct drm_crtc *crtc, u32 flush_mask)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
@@ -110,8 +108,8 @@ static void crtc_flush_all(struct drm_crtc *crtc)
        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);
+
+       flush_mask |= mdp_ctl_flush_mask_lm(mdp5_crtc->lm);
 
        crtc_flush(crtc, flush_mask);
 }
@@ -298,8 +296,6 @@ static void mdp5_crtc_enable(struct drm_crtc *crtc)
        mdp5_enable(mdp5_kms);
        mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err);
 
-       crtc_flush_all(crtc);
-
        mdp5_crtc->enabled = true;
 }
 
@@ -444,13 +440,14 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct mdp5_kms *mdp5_kms = get_kms(crtc);
-       struct drm_gem_object *cursor_bo, *old_bo;
+       struct drm_gem_object *cursor_bo, *old_bo = NULL;
        uint32_t blendcfg, cursor_addr, stride;
        int ret, bpp, lm;
        unsigned int depth;
        enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL;
        uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
        uint32_t roi_w, roi_h;
+       bool cursor_enable = true;
        unsigned long flags;
 
        if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
@@ -463,7 +460,8 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
 
        if (!handle) {
                DBG("Cursor off");
-               return mdp5_ctl_set_cursor(mdp5_crtc->ctl, false);
+               cursor_enable = false;
+               goto set_cursor;
        }
 
        cursor_bo = drm_gem_object_lookup(dev, file, handle);
@@ -504,11 +502,14 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
 
        spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
 
-       ret = mdp5_ctl_set_cursor(mdp5_crtc->ctl, true);
-       if (ret)
+set_cursor:
+       ret = mdp5_ctl_set_cursor(mdp5_crtc->ctl, 0, cursor_enable);
+       if (ret) {
+               dev_err(dev->dev, "failed to %sable cursor: %d\n",
+                               cursor_enable ? "en" : "dis", ret);
                goto end;
+       }
 
-       flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl);
        crtc_flush(crtc, flush_mask);
 
 end:
@@ -613,64 +614,39 @@ void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file)
 }
 
 /* set interface for routing crtc->encoder: */
-void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf,
-               enum mdp5_intf intf_id)
+void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
        struct mdp5_kms *mdp5_kms = get_kms(crtc);
-       uint32_t flush_mask = 0;
-       uint32_t intf_sel;
-       unsigned long flags;
+       int lm = mdp5_crtc_get_lm(crtc);
 
        /* now that we know what irq's we want: */
-       mdp5_crtc->err.irqmask = intf2err(intf);
-       mdp5_crtc->vblank.irqmask = intf2vblank(intf);
-       mdp_irq_update(&mdp5_kms->base);
-
-       spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
-       intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL);
-
-       switch (intf) {
-       case 0:
-               intf_sel &= ~MDP5_DISP_INTF_SEL_INTF0__MASK;
-               intf_sel |= MDP5_DISP_INTF_SEL_INTF0(intf_id);
-               break;
-       case 1:
-               intf_sel &= ~MDP5_DISP_INTF_SEL_INTF1__MASK;
-               intf_sel |= MDP5_DISP_INTF_SEL_INTF1(intf_id);
-               break;
-       case 2:
-               intf_sel &= ~MDP5_DISP_INTF_SEL_INTF2__MASK;
-               intf_sel |= MDP5_DISP_INTF_SEL_INTF2(intf_id);
-               break;
-       case 3:
-               intf_sel &= ~MDP5_DISP_INTF_SEL_INTF3__MASK;
-               intf_sel |= MDP5_DISP_INTF_SEL_INTF3(intf_id);
-               break;
-       default:
-               BUG();
-               break;
-       }
+       mdp5_crtc->err.irqmask = intf2err(intf->num);
 
-       mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, intf_sel);
-       spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
+       /* Register command mode Pingpong done as vblank for now,
+        * so that atomic commit should wait for it to finish.
+        * Ideally, in the future, we should take rd_ptr done as vblank,
+        * and let atomic commit wait for pingpong done for commond mode.
+        */
+       if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
+               mdp5_crtc->vblank.irqmask = lm2ppdone(lm);
+       else
+               mdp5_crtc->vblank.irqmask = intf2vblank(lm, intf);
+       mdp_irq_update(&mdp5_kms->base);
 
-       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);
-
-       crtc_flush(crtc, flush_mask);
 }
 
 int mdp5_crtc_get_lm(struct drm_crtc *crtc)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       return WARN_ON(!crtc) ? -EINVAL : mdp5_crtc->lm;
+}
 
-       if (WARN_ON(!crtc))
-               return -EINVAL;
-
-       return mdp5_crtc->lm;
+struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       return WARN_ON(!crtc) ? NULL : mdp5_crtc->ctl;
 }
 
 /* initialize crtc */
index 151129032d165875477d870c8c6cca5b2245e1e6..5488b687c8d11e8c2c6db2217654c82d4e8de323 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015 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
  * requested by the client (in mdp5_crtc_mode_set()).
  */
 
+struct op_mode {
+       struct mdp5_interface intf;
+
+       bool encoder_enabled;
+       uint32_t start_mask;
+};
+
 struct mdp5_ctl {
        struct mdp5_ctl_manager *ctlm;
 
        u32 id;
+       int lm;
 
        /* whether this CTL has been allocated or not: */
        bool busy;
 
-       /* memory output connection (@see mdp5_ctl_mode): */
-       u32 mode;
+       /* Operation Mode Configuration for the Pipeline */
+       struct op_mode pipeline;
 
        /* 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;
+       /* when do CTL registers need to be flushed? (mask of trigger bits) */
+       u32 pending_ctl_trigger;
 
        bool cursor_on;
 
@@ -63,6 +71,9 @@ struct mdp5_ctl_manager {
        u32 nlm;
        u32 nctl;
 
+       /* to filter out non-present bits in the current hardware config */
+       u32 flush_hw_mask;
+
        /* pool of CTLs + lock to protect resource allocation (ctls[i].busy) */
        spinlock_t pool_lock;
        struct mdp5_ctl ctls[MAX_CTL];
@@ -94,31 +105,172 @@ u32 ctl_read(struct mdp5_ctl *ctl, u32 reg)
        return mdp5_read(mdp5_kms, reg);
 }
 
+static void set_display_intf(struct mdp5_kms *mdp5_kms,
+               struct mdp5_interface *intf)
+{
+       unsigned long flags;
+       u32 intf_sel;
+
+       spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
+       intf_sel = mdp5_read(mdp5_kms, REG_MDP5_MDP_DISP_INTF_SEL(0));
+
+       switch (intf->num) {
+       case 0:
+               intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF0__MASK;
+               intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF0(intf->type);
+               break;
+       case 1:
+               intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF1__MASK;
+               intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF1(intf->type);
+               break;
+       case 2:
+               intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF2__MASK;
+               intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF2(intf->type);
+               break;
+       case 3:
+               intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF3__MASK;
+               intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF3(intf->type);
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       mdp5_write(mdp5_kms, REG_MDP5_MDP_DISP_INTF_SEL(0), intf_sel);
+       spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
+}
 
-int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, int intf)
+static void set_ctl_op(struct mdp5_ctl *ctl, struct mdp5_interface *intf)
 {
        unsigned long flags;
-       static const enum mdp5_intfnum intfnum[] = {
-                       INTF0, INTF1, INTF2, INTF3,
-       };
+       u32 ctl_op = 0;
+
+       if (!mdp5_cfg_intf_is_virtual(intf->type))
+               ctl_op |= MDP5_CTL_OP_INTF_NUM(INTF0 + intf->num);
+
+       switch (intf->type) {
+       case INTF_DSI:
+               if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
+                       ctl_op |= MDP5_CTL_OP_CMD_MODE;
+               break;
+
+       case INTF_WB:
+               if (intf->mode == MDP5_INTF_WB_MODE_LINE)
+                       ctl_op |= MDP5_CTL_OP_MODE(MODE_WB_2_LINE);
+               break;
+
+       default:
+               break;
+       }
 
        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]));
+       ctl_write(ctl, REG_MDP5_CTL_OP(ctl->id), ctl_op);
        spin_unlock_irqrestore(&ctl->hw_lock, flags);
+}
+
+int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf)
+{
+       struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
+       struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr);
+
+       memcpy(&ctl->pipeline.intf, intf, sizeof(*intf));
+
+       ctl->pipeline.start_mask = mdp_ctl_flush_mask_lm(ctl->lm) |
+                                  mdp_ctl_flush_mask_encoder(intf);
+
+       /* Virtual interfaces need not set a display intf (e.g.: Writeback) */
+       if (!mdp5_cfg_intf_is_virtual(intf->type))
+               set_display_intf(mdp5_kms, intf);
+
+       set_ctl_op(ctl, intf);
 
        return 0;
 }
 
-int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable)
+static bool start_signal_needed(struct mdp5_ctl *ctl)
+{
+       struct op_mode *pipeline = &ctl->pipeline;
+
+       if (!pipeline->encoder_enabled || pipeline->start_mask != 0)
+               return false;
+
+       switch (pipeline->intf.type) {
+       case INTF_WB:
+               return true;
+       case INTF_DSI:
+               return pipeline->intf.mode == MDP5_INTF_DSI_MODE_COMMAND;
+       default:
+               return false;
+       }
+}
+
+/*
+ * send_start_signal() - Overlay Processor Start Signal
+ *
+ * For a given control operation (display pipeline), a START signal needs to be
+ * executed in order to kick off operation and activate all layers.
+ * e.g.: DSI command mode, Writeback
+ */
+static void send_start_signal(struct mdp5_ctl *ctl)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ctl->hw_lock, flags);
+       ctl_write(ctl, REG_MDP5_CTL_START(ctl->id), 1);
+       spin_unlock_irqrestore(&ctl->hw_lock, flags);
+}
+
+static void refill_start_mask(struct mdp5_ctl *ctl)
+{
+       struct op_mode *pipeline = &ctl->pipeline;
+       struct mdp5_interface *intf = &ctl->pipeline.intf;
+
+       pipeline->start_mask = mdp_ctl_flush_mask_lm(ctl->lm);
+
+       /*
+        * Writeback encoder needs to program & flush
+        * address registers for each page flip..
+        */
+       if (intf->type == INTF_WB)
+               pipeline->start_mask |= mdp_ctl_flush_mask_encoder(intf);
+}
+
+/**
+ * mdp5_ctl_set_encoder_state() - set the encoder state
+ *
+ * @enable: true, when encoder is ready for data streaming; false, otherwise.
+ *
+ * Note:
+ * This encoder state is needed to trigger START signal (data path kickoff).
+ */
+int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, bool enabled)
+{
+       if (WARN_ON(!ctl))
+               return -EINVAL;
+
+       ctl->pipeline.encoder_enabled = enabled;
+       DBG("intf_%d: %s", ctl->pipeline.intf.num, enabled ? "on" : "off");
+
+       if (start_signal_needed(ctl)) {
+               send_start_signal(ctl);
+               refill_start_mask(ctl);
+       }
+
+       return 0;
+}
+
+/*
+ * Note:
+ * CTL registers need to be flushed after calling this function
+ * (call mdp5_ctl_commit() with mdp_ctl_flush_mask_ctl() mask)
+ */
+int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, int cursor_id, bool enable)
 {
        struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
        unsigned long flags;
        u32 blend_cfg;
-       int lm;
+       int lm = ctl->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);
@@ -138,12 +290,12 @@ int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable)
 
        spin_unlock_irqrestore(&ctl->hw_lock, flags);
 
+       ctl->pending_ctl_trigger = mdp_ctl_flush_mask_cursor(cursor_id);
        ctl->cursor_on = enable;
 
        return 0;
 }
 
-
 int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg)
 {
        unsigned long flags;
@@ -157,37 +309,122 @@ int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg)
        ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, lm), blend_cfg);
        spin_unlock_irqrestore(&ctl->hw_lock, flags);
 
+       ctl->pending_ctl_trigger = mdp_ctl_flush_mask_lm(lm);
+
        return 0;
 }
 
+u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf)
+{
+       if (intf->type == INTF_WB)
+               return MDP5_CTL_FLUSH_WB;
+
+       switch (intf->num) {
+       case 0: return MDP5_CTL_FLUSH_TIMING_0;
+       case 1: return MDP5_CTL_FLUSH_TIMING_1;
+       case 2: return MDP5_CTL_FLUSH_TIMING_2;
+       case 3: return MDP5_CTL_FLUSH_TIMING_3;
+       default: return 0;
+       }
+}
+
+u32 mdp_ctl_flush_mask_cursor(int cursor_id)
+{
+       switch (cursor_id) {
+       case 0: return MDP5_CTL_FLUSH_CURSOR_0;
+       case 1: return MDP5_CTL_FLUSH_CURSOR_1;
+       default: return 0;
+       }
+}
+
+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;
+       }
+}
+
+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 u32 fix_sw_flush(struct mdp5_ctl *ctl, u32 flush_mask)
+{
+       struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
+       u32 sw_mask = 0;
+#define BIT_NEEDS_SW_FIX(bit) \
+       (!(ctl_mgr->flush_hw_mask & bit) && (flush_mask & bit))
+
+       /* for some targets, cursor bit is the same as LM bit */
+       if (BIT_NEEDS_SW_FIX(MDP5_CTL_FLUSH_CURSOR_0))
+               sw_mask |= mdp_ctl_flush_mask_lm(ctl->lm);
+
+       return sw_mask;
+}
+
+/**
+ * mdp5_ctl_commit() - Register Flush
+ *
+ * The flush register is used to indicate several registers are all
+ * programmed, and are safe to update to the back copy of the double
+ * buffered registers.
+ *
+ * Some registers FLUSH bits are shared when the hardware does not have
+ * dedicated bits for them; handling these is the job of fix_sw_flush().
+ *
+ * CTL registers need to be flushed in some circumstances; if that is the
+ * case, some trigger bits will be present in both flush mask and
+ * ctl->pending_ctl_trigger.
+ */
 int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask)
 {
        struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
+       struct op_mode *pipeline = &ctl->pipeline;
        unsigned long flags;
 
-       if (flush_mask & MDP5_CTL_FLUSH_CURSOR_DUMMY) {
-               int lm = mdp5_crtc_get_lm(ctl->crtc);
+       pipeline->start_mask &= ~flush_mask;
 
-               if (unlikely(WARN_ON(lm < 0))) {
-                       dev_err(ctl_mgr->dev->dev, "CTL %d cannot find LM: %d",
-                                       ctl->id, lm);
-                       return -EINVAL;
-               }
+       VERB("flush_mask=%x, start_mask=%x, trigger=%x", flush_mask,
+                       pipeline->start_mask, ctl->pending_ctl_trigger);
 
-               /* for current targets, cursor bit is the same as LM bit */
-               flush_mask |= mdp_ctl_flush_mask_lm(lm);
+       if (ctl->pending_ctl_trigger & flush_mask) {
+               flush_mask |= MDP5_CTL_FLUSH_CTL;
+               ctl->pending_ctl_trigger = 0;
        }
 
-       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);
+       flush_mask |= fix_sw_flush(ctl, flush_mask);
 
-       return 0;
-}
+       flush_mask &= ctl_mgr->flush_hw_mask;
 
-u32 mdp5_ctl_get_flush(struct mdp5_ctl *ctl)
-{
-       return ctl->flush_mask;
+       if (flush_mask) {
+               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);
+       }
+
+       if (start_signal_needed(ctl)) {
+               send_start_signal(ctl);
+               refill_start_mask(ctl);
+       }
+
+       return 0;
 }
 
 void mdp5_ctl_release(struct mdp5_ctl *ctl)
@@ -208,6 +445,11 @@ void mdp5_ctl_release(struct mdp5_ctl *ctl)
        DBG("CTL %d released", ctl->id);
 }
 
+int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl)
+{
+       return WARN_ON(!ctl) ? -EINVAL : ctl->id;
+}
+
 /*
  * mdp5_ctl_request() - CTL dynamic allocation
  *
@@ -235,8 +477,10 @@ struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctl_mgr,
 
        ctl = &ctl_mgr->ctls[c];
 
+       ctl->lm = mdp5_crtc_get_lm(crtc);
        ctl->crtc = crtc;
        ctl->busy = true;
+       ctl->pending_ctl_trigger = 0;
        DBG("CTL %d allocated", ctl->id);
 
 unlock:
@@ -267,7 +511,7 @@ 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;
+       const struct mdp5_ctl_block *ctl_cfg = &hw_cfg->ctl;
        unsigned long flags;
        int c, ret;
 
@@ -289,6 +533,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
        ctl_mgr->dev = dev;
        ctl_mgr->nlm = hw_cfg->lm.count;
        ctl_mgr->nctl = ctl_cfg->count;
+       ctl_mgr->flush_hw_mask = ctl_cfg->flush_hw_mask;
        spin_lock_init(&ctl_mgr->pool_lock);
 
        /* initialize each CTL of the pool: */
@@ -303,9 +548,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
                }
                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);
        }
index ad48788efeea85e049727a26f5ed4053d303f99f..7a62000994a16fc906ee919d4e2ad65860f6b944 100644 (file)
@@ -33,19 +33,13 @@ void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctlm);
  * 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_get_ctl_id(struct mdp5_ctl *ctl);
 
-int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, int intf);
+struct mdp5_interface;
+int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf);
+int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, bool enabled);
 
-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);
+int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, int cursor_id, bool enable);
 
 /*
  * blend_cfg (LM blender config):
@@ -72,51 +66,32 @@ static inline u32 mdp_ctl_blend_mask(enum mdp5_pipe pipe,
 }
 
 /*
- * flush_mask (CTL flush masks):
+ * mdp5_ctl_blend() - Blend multiple layers on a Layer Mixer (LM)
+ *
+ * @blend_cfg: see LM blender config definition below
  *
- * 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.
+ * Note:
+ * CTL registers need to be flushed after calling this function
+ * (call mdp5_ctl_commit() with mdp_ctl_flush_mask_ctl() mask)
  */
+int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg);
 
-#define MDP5_CTL_FLUSH_CURSOR_DUMMY    0x80000000
+/**
+ * mdp_ctl_flush_mask...() - Register FLUSH masks
+ *
+ * These masks are used to specify which block(s) need to be flushed
+ * through @flush_mask parameter in mdp5_ctl_commit(.., flush_mask).
+ */
+u32 mdp_ctl_flush_mask_lm(int lm);
+u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe);
+u32 mdp_ctl_flush_mask_cursor(int cursor_id);
+u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf);
 
-static inline u32 mdp_ctl_flush_mask_cursor(int cursor_id)
-{
-       /* TODO: use id once multiple cursor support is present */
-       (void)cursor_id;
+/* @flush_mask: see CTL flush masks definitions below */
+int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask);
 
-       return MDP5_CTL_FLUSH_CURSOR_DUMMY;
-}
+void mdp5_ctl_release(struct mdp5_ctl *ctl);
 
-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 af0e02fa4f4821ac7a71a4b641fde76db366a8cd..1188f4bf1e603853e1d872dd0ad06ee55de9cceb 100644 (file)
@@ -23,8 +23,7 @@
 
 struct mdp5_encoder {
        struct drm_encoder base;
-       int intf;
-       enum mdp5_intf intf_id;
+       struct mdp5_interface intf;
        spinlock_t intf_lock;   /* protect REG_MDP5_INTF_* registers */
        bool enabled;
        uint32_t bsc;
@@ -126,7 +125,7 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
        struct mdp5_kms *mdp5_kms = get_kms(encoder);
        struct drm_device *dev = encoder->dev;
        struct drm_connector *connector;
-       int intf = mdp5_encoder->intf;
+       int intf = mdp5_encoder->intf.num;
        uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol;
        uint32_t display_v_start, display_v_end;
        uint32_t hsync_start_x, hsync_end_x;
@@ -188,7 +187,7 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
         * DISPLAY_V_START = (VBP * HCYCLE) + HBP
         * DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP
         */
-       if (mdp5_encoder->intf_id == INTF_eDP) {
+       if (mdp5_encoder->intf.type == INTF_eDP) {
                display_v_start += mode->htotal - mode->hsync_start;
                display_v_end -= mode->hsync_start - mode->hdisplay;
        }
@@ -218,21 +217,29 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
        mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(intf), 0x3);  /* frame+line? */
 
        spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
+
+       mdp5_crtc_set_intf(encoder->crtc, &mdp5_encoder->intf);
 }
 
 static void mdp5_encoder_disable(struct drm_encoder *encoder)
 {
        struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
        struct mdp5_kms *mdp5_kms = get_kms(encoder);
-       int intf = mdp5_encoder->intf;
+       struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
+       int lm = mdp5_crtc_get_lm(encoder->crtc);
+       struct mdp5_interface *intf = &mdp5_encoder->intf;
+       int intfn = mdp5_encoder->intf.num;
        unsigned long flags;
 
        if (WARN_ON(!mdp5_encoder->enabled))
                return;
 
+       mdp5_ctl_set_encoder_state(ctl, false);
+
        spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
-       mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 0);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 0);
        spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
+       mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf));
 
        /*
         * Wait for a vsync so we know the ENABLE=0 latched before
@@ -242,7 +249,7 @@ static void mdp5_encoder_disable(struct drm_encoder *encoder)
         * the settings changes for the new modeset (like new
         * scanout buffer) don't latch properly..
         */
-       mdp_irq_wait(&mdp5_kms->base, intf2vblank(intf));
+       mdp_irq_wait(&mdp5_kms->base, intf2vblank(lm, intf));
 
        bs_set(mdp5_encoder, 0);
 
@@ -253,19 +260,21 @@ static void mdp5_encoder_enable(struct drm_encoder *encoder)
 {
        struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
        struct mdp5_kms *mdp5_kms = get_kms(encoder);
-       int intf = mdp5_encoder->intf;
+       struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
+       struct mdp5_interface *intf = &mdp5_encoder->intf;
+       int intfn = mdp5_encoder->intf.num;
        unsigned long flags;
 
        if (WARN_ON(mdp5_encoder->enabled))
                return;
 
-       mdp5_crtc_set_intf(encoder->crtc, mdp5_encoder->intf,
-                       mdp5_encoder->intf_id);
-
        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);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 1);
        spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
+       mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf));
+
+       mdp5_ctl_set_encoder_state(ctl, true);
 
        mdp5_encoder->enabled = true;
 }
@@ -277,12 +286,51 @@ static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
        .enable = mdp5_encoder_enable,
 };
 
+int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
+                                       struct drm_encoder *slave_encoder)
+{
+       struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+       struct mdp5_kms *mdp5_kms;
+       int intf_num;
+       u32 data = 0;
+
+       if (!encoder || !slave_encoder)
+               return -EINVAL;
+
+       mdp5_kms = get_kms(encoder);
+       intf_num = mdp5_encoder->intf.num;
+
+       /* Switch slave encoder's TimingGen Sync mode,
+        * to use the master's enable signal for the slave encoder.
+        */
+       if (intf_num == 1)
+               data |= MDP5_SPLIT_DPL_LOWER_INTF2_TG_SYNC;
+       else if (intf_num == 2)
+               data |= MDP5_SPLIT_DPL_LOWER_INTF1_TG_SYNC;
+       else
+               return -EINVAL;
+
+       /* Make sure clocks are on when connectors calling this function. */
+       mdp5_enable(mdp5_kms);
+       mdp5_write(mdp5_kms, REG_MDP5_MDP_SPARE_0(0),
+               MDP5_MDP_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN);
+       /* Dumb Panel, Sync mode */
+       mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, 0);
+       mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, data);
+       mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1);
+       mdp5_disable(mdp5_kms);
+
+       return 0;
+}
+
 /* initialize encoder */
-struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf,
-               enum mdp5_intf intf_id)
+struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
+                               struct mdp5_interface *intf)
 {
        struct drm_encoder *encoder = NULL;
        struct mdp5_encoder *mdp5_encoder;
+       int enc_type = (intf->type == INTF_DSI) ?
+               DRM_MODE_ENCODER_DSI : DRM_MODE_ENCODER_TMDS;
        int ret;
 
        mdp5_encoder = kzalloc(sizeof(*mdp5_encoder), GFP_KERNEL);
@@ -291,14 +339,13 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf,
                goto fail;
        }
 
-       mdp5_encoder->intf = intf;
-       mdp5_encoder->intf_id = intf_id;
+       memcpy(&mdp5_encoder->intf, intf, sizeof(mdp5_encoder->intf));
        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_init(dev, encoder, &mdp5_encoder_funcs, enc_type);
+
        drm_encoder_helper_add(encoder, &mdp5_encoder_helper_funcs);
 
        bs_init(mdp5_encoder);
index a9407105b9b799bea9fc787a923e7dc914bee30a..33bd4c6160dd0ded0fce6f676e02ee803c2572c7 100644 (file)
@@ -23,7 +23,7 @@
 
 void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask)
 {
-       mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_INTR_EN, irqmask);
+       mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_MDP_INTR_EN(0), irqmask);
 }
 
 static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
@@ -35,8 +35,8 @@ void mdp5_irq_preinstall(struct msm_kms *kms)
 {
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
        mdp5_enable(mdp5_kms);
-       mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, 0xffffffff);
-       mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
+       mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_CLEAR(0), 0xffffffff);
+       mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_EN(0), 0x00000000);
        mdp5_disable(mdp5_kms);
 }
 
@@ -61,7 +61,7 @@ void mdp5_irq_uninstall(struct msm_kms *kms)
 {
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
        mdp5_enable(mdp5_kms);
-       mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
+       mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_EN(0), 0x00000000);
        mdp5_disable(mdp5_kms);
 }
 
@@ -73,8 +73,8 @@ static void mdp5_irq_mdp(struct mdp_kms *mdp_kms)
        unsigned int id;
        uint32_t status;
 
-       status = mdp5_read(mdp5_kms, REG_MDP5_INTR_STATUS);
-       mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, status);
+       status = mdp5_read(mdp5_kms, REG_MDP5_MDP_INTR_STATUS(0));
+       mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_CLEAR(0), status);
 
        VERB("status=%08x", status);
 
@@ -91,13 +91,13 @@ irqreturn_t mdp5_irq(struct msm_kms *kms)
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms);
        uint32_t intr;
 
-       intr = mdp5_read(mdp5_kms, REG_MDP5_HW_INTR_STATUS);
+       intr = mdp5_read(mdp5_kms, REG_MDSS_HW_INTR_STATUS);
 
        VERB("intr=%08x", intr);
 
-       if (intr & MDP5_HW_INTR_STATUS_INTR_MDP) {
+       if (intr & MDSS_HW_INTR_STATUS_INTR_MDP) {
                mdp5_irq_mdp(mdp_kms);
-               intr &= ~MDP5_HW_INTR_STATUS_INTR_MDP;
+               intr &= ~MDSS_HW_INTR_STATUS_INTR_MDP;
        }
 
        while (intr) {
@@ -128,10 +128,10 @@ void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
  * 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)
+#define VALID_IRQS  (MDSS_HW_INTR_STATUS_INTR_DSI0 | \
+               MDSS_HW_INTR_STATUS_INTR_DSI1 | \
+               MDSS_HW_INTR_STATUS_INTR_HDMI | \
+               MDSS_HW_INTR_STATUS_INTR_EDP)
 
 static void mdp5_hw_mask_irq(struct irq_data *irqd)
 {
index 92b61db5754cbf71f9368011fda966cbb9cbabfa..dfa8beb9343aaa171110adabb49c549e4143c0da 100644 (file)
@@ -58,7 +58,7 @@ static int mdp5_hw_init(struct msm_kms *kms)
         */
 
        spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
-       mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, 0);
+       mdp5_write(mdp5_kms, REG_MDP5_MDP_DISP_INTF_SEL(0), 0);
        spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
 
        mdp5_ctlm_hw_reset(mdp5_kms->ctlm);
@@ -86,6 +86,18 @@ static long mdp5_round_pixclk(struct msm_kms *kms, unsigned long rate,
        return rate;
 }
 
+static int mdp5_set_split_display(struct msm_kms *kms,
+               struct drm_encoder *encoder,
+               struct drm_encoder *slave_encoder,
+               bool is_cmd_mode)
+{
+       if (is_cmd_mode)
+               return mdp5_cmd_encoder_set_split_display(encoder,
+                                                       slave_encoder);
+       else
+               return mdp5_encoder_set_split_display(encoder, slave_encoder);
+}
+
 static void mdp5_preclose(struct msm_kms *kms, struct drm_file *file)
 {
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
@@ -131,6 +143,7 @@ static const struct mdp_kms_funcs kms_funcs = {
                .complete_commit = mdp5_complete_commit,
                .get_format      = mdp_get_format,
                .round_pixclk    = mdp5_round_pixclk,
+               .set_split_display = mdp5_set_split_display,
                .preclose        = mdp5_preclose,
                .destroy         = mdp5_destroy,
        },
@@ -161,6 +174,134 @@ int mdp5_enable(struct mdp5_kms *mdp5_kms)
        return 0;
 }
 
+static struct drm_encoder *construct_encoder(struct mdp5_kms *mdp5_kms,
+               enum mdp5_intf_type intf_type, int intf_num,
+               enum mdp5_intf_mode intf_mode)
+{
+       struct drm_device *dev = mdp5_kms->dev;
+       struct msm_drm_private *priv = dev->dev_private;
+       struct drm_encoder *encoder;
+       struct mdp5_interface intf = {
+                       .num    = intf_num,
+                       .type   = intf_type,
+                       .mode   = intf_mode,
+       };
+
+       if ((intf_type == INTF_DSI) &&
+               (intf_mode == MDP5_INTF_DSI_MODE_COMMAND))
+               encoder = mdp5_cmd_encoder_init(dev, &intf);
+       else
+               encoder = mdp5_encoder_init(dev, &intf);
+
+       if (IS_ERR(encoder)) {
+               dev_err(dev->dev, "failed to construct encoder\n");
+               return encoder;
+       }
+
+       encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
+       priv->encoders[priv->num_encoders++] = encoder;
+
+       return encoder;
+}
+
+static int get_dsi_id_from_intf(const struct mdp5_cfg_hw *hw_cfg, int intf_num)
+{
+       const int intf_cnt = hw_cfg->intf.count;
+       const u32 *intfs = hw_cfg->intfs;
+       int id = 0, i;
+
+       for (i = 0; i < intf_cnt; i++) {
+               if (intfs[i] == INTF_DSI) {
+                       if (intf_num == i)
+                               return id;
+
+                       id++;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
+{
+       struct drm_device *dev = mdp5_kms->dev;
+       struct msm_drm_private *priv = dev->dev_private;
+       const struct mdp5_cfg_hw *hw_cfg =
+                                       mdp5_cfg_get_hw_config(mdp5_kms->cfg);
+       enum mdp5_intf_type intf_type = hw_cfg->intfs[intf_num];
+       struct drm_encoder *encoder;
+       int ret = 0;
+
+       switch (intf_type) {
+       case INTF_DISABLED:
+               break;
+       case INTF_eDP:
+               if (!priv->edp)
+                       break;
+
+               encoder = construct_encoder(mdp5_kms, INTF_eDP, intf_num,
+                                       MDP5_INTF_MODE_NONE);
+               if (IS_ERR(encoder)) {
+                       ret = PTR_ERR(encoder);
+                       break;
+               }
+
+               ret = msm_edp_modeset_init(priv->edp, dev, encoder);
+               break;
+       case INTF_HDMI:
+               if (!priv->hdmi)
+                       break;
+
+               encoder = construct_encoder(mdp5_kms, INTF_HDMI, intf_num,
+                                       MDP5_INTF_MODE_NONE);
+               if (IS_ERR(encoder)) {
+                       ret = PTR_ERR(encoder);
+                       break;
+               }
+
+               ret = hdmi_modeset_init(priv->hdmi, dev, encoder);
+               break;
+       case INTF_DSI:
+       {
+               int dsi_id = get_dsi_id_from_intf(hw_cfg, intf_num);
+               struct drm_encoder *dsi_encs[MSM_DSI_ENCODER_NUM];
+               enum mdp5_intf_mode mode;
+               int i;
+
+               if ((dsi_id >= ARRAY_SIZE(priv->dsi)) || (dsi_id < 0)) {
+                       dev_err(dev->dev, "failed to find dsi from intf %d\n",
+                               intf_num);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (!priv->dsi[dsi_id])
+                       break;
+
+               for (i = 0; i < MSM_DSI_ENCODER_NUM; i++) {
+                       mode = (i == MSM_DSI_CMD_ENCODER_ID) ?
+                               MDP5_INTF_DSI_MODE_COMMAND :
+                               MDP5_INTF_DSI_MODE_VIDEO;
+                       dsi_encs[i] = construct_encoder(mdp5_kms, INTF_DSI,
+                                                       intf_num, mode);
+                       if (IS_ERR(dsi_encs)) {
+                               ret = PTR_ERR(dsi_encs);
+                               break;
+                       }
+               }
+
+               ret = msm_dsi_modeset_init(priv->dsi[dsi_id], dev, dsi_encs);
+               break;
+       }
+       default:
+               dev_err(dev->dev, "unknown intf: %d\n", intf_type);
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
 static int modeset_init(struct mdp5_kms *mdp5_kms)
 {
        static const enum mdp5_pipe crtcs[] = {
@@ -171,7 +312,6 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
        };
        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;
 
@@ -222,44 +362,13 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
                }
        }
 
-       if (priv->hdmi) {
-               /* Construct encoder for HDMI: */
-               encoder = mdp5_encoder_init(dev, 3, INTF_HDMI);
-               if (IS_ERR(encoder)) {
-                       dev_err(dev->dev, "failed to construct encoder\n");
-                       ret = PTR_ERR(encoder);
-                       goto fail;
-               }
-
-               encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;;
-               priv->encoders[priv->num_encoders++] = encoder;
-
-               ret = hdmi_modeset_init(priv->hdmi, dev, encoder);
-               if (ret) {
-                       dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
-                       goto fail;
-               }
-       }
-
-       if (priv->edp) {
-               /* Construct encoder for eDP: */
-               encoder = mdp5_encoder_init(dev, 0, INTF_eDP);
-               if (IS_ERR(encoder)) {
-                       dev_err(dev->dev, "failed to construct eDP encoder\n");
-                       ret = PTR_ERR(encoder);
-                       goto fail;
-               }
-
-               encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
-               priv->encoders[priv->num_encoders++] = encoder;
-
-               /* Construct bridge/connector for eDP: */
-               ret = msm_edp_modeset_init(priv->edp, dev, encoder);
-               if (ret) {
-                       dev_err(dev->dev, "failed to initialize eDP: %d\n",
-                                                                       ret);
+       /* Construct encoders and modeset initialize connector devices
+        * for each external display interface.
+        */
+       for (i = 0; i < ARRAY_SIZE(hw_cfg->intfs); i++) {
+               ret = modeset_init_intf(mdp5_kms, i);
+               if (ret)
                        goto fail;
-               }
        }
 
        return 0;
@@ -274,11 +383,11 @@ static void read_hw_revision(struct mdp5_kms *mdp5_kms,
        uint32_t version;
 
        mdp5_enable(mdp5_kms);
-       version = mdp5_read(mdp5_kms, REG_MDP5_MDP_VERSION);
+       version = mdp5_read(mdp5_kms, REG_MDSS_HW_VERSION);
        mdp5_disable(mdp5_kms);
 
-       *major = FIELD(version, MDP5_MDP_VERSION_MAJOR);
-       *minor = FIELD(version, MDP5_MDP_VERSION_MINOR);
+       *major = FIELD(version, MDSS_HW_VERSION_MAJOR);
+       *minor = FIELD(version, MDSS_HW_VERSION_MINOR);
 
        DBG("MDP5 version v%d.%d", *major, *minor);
 }
@@ -321,6 +430,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
 
        mdp5_kms->dev = dev;
 
+       /* mdp5_kms->mmio actually represents the MDSS base address */
        mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys", "MDP5");
        if (IS_ERR(mdp5_kms->mmio)) {
                ret = PTR_ERR(mdp5_kms->mmio);
@@ -403,8 +513,12 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
         * we don't disable):
         */
        mdp5_enable(mdp5_kms);
-       for (i = 0; i < config->hw->intf.count; i++)
+       for (i = 0; i < MDP5_INTF_NUM_MAX; i++) {
+               if (!config->hw->intf.base[i] ||
+                               mdp5_cfg_intf_is_virtual(config->hw->intfs[i]))
+                       continue;
                mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0);
+       }
        mdp5_disable(mdp5_kms);
        mdelay(16);
 
index 49d011e8835b298707fb00956f606135a67ada93..2c0de174cc09b9e198d05e3eed1745e193d997ba 100644 (file)
@@ -54,7 +54,7 @@ struct mdp5_kms {
 
        /*
         * lock to protect access to global resources: ie., following register:
-        *      - REG_MDP5_DISP_INTF_SEL
+        *      - REG_MDP5_MDP_DISP_INTF_SEL
         */
        spinlock_t resource_lock;
 
@@ -94,6 +94,24 @@ struct mdp5_plane_state {
 #define to_mdp5_plane_state(x) \
                container_of(x, struct mdp5_plane_state, base)
 
+enum mdp5_intf_mode {
+       MDP5_INTF_MODE_NONE = 0,
+
+       /* Modes used for DSI interface (INTF_DSI type): */
+       MDP5_INTF_DSI_MODE_VIDEO,
+       MDP5_INTF_DSI_MODE_COMMAND,
+
+       /* Modes used for WB interface (INTF_WB type):  */
+       MDP5_INTF_WB_MODE_BLOCK,
+       MDP5_INTF_WB_MODE_LINE,
+};
+
+struct mdp5_interface {
+       int num; /* display interface number */
+       enum mdp5_intf_type type;
+       enum mdp5_intf_mode mode;
+};
+
 static inline void mdp5_write(struct mdp5_kms *mdp5_kms, u32 reg, u32 data)
 {
        msm_writel(data, mdp5_kms->mmio + reg);
@@ -130,9 +148,9 @@ static inline int pipe2nclients(enum mdp5_pipe pipe)
        }
 }
 
-static inline uint32_t intf2err(int intf)
+static inline uint32_t intf2err(int intf_num)
 {
-       switch (intf) {
+       switch (intf_num) {
        case 0:  return MDP5_IRQ_INTF0_UNDER_RUN;
        case 1:  return MDP5_IRQ_INTF1_UNDER_RUN;
        case 2:  return MDP5_IRQ_INTF2_UNDER_RUN;
@@ -141,9 +159,23 @@ static inline uint32_t intf2err(int intf)
        }
 }
 
-static inline uint32_t intf2vblank(int intf)
+#define GET_PING_PONG_ID(layer_mixer)  ((layer_mixer == 5) ? 3 : layer_mixer)
+static inline uint32_t intf2vblank(int lm, struct mdp5_interface *intf)
 {
-       switch (intf) {
+       /*
+        * In case of DSI Command Mode, the Ping Pong's read pointer IRQ
+        * acts as a Vblank signal. The Ping Pong buffer used is bound to
+        * layer mixer.
+        */
+
+       if ((intf->type == INTF_DSI) &&
+                       (intf->mode == MDP5_INTF_DSI_MODE_COMMAND))
+               return MDP5_IRQ_PING_PONG_0_RD_PTR << GET_PING_PONG_ID(lm);
+
+       if (intf->type == INTF_WB)
+               return MDP5_IRQ_WB_2_DONE;
+
+       switch (intf->num) {
        case 0:  return MDP5_IRQ_INTF0_VSYNC;
        case 1:  return MDP5_IRQ_INTF1_VSYNC;
        case 2:  return MDP5_IRQ_INTF2_VSYNC;
@@ -152,6 +184,11 @@ static inline uint32_t intf2vblank(int intf)
        }
 }
 
+static inline uint32_t lm2ppdone(int lm)
+{
+       return MDP5_IRQ_PING_PONG_0_DONE << GET_PING_PONG_ID(lm);
+}
+
 int mdp5_disable(struct mdp5_kms *mdp5_kms);
 int mdp5_enable(struct mdp5_kms *mdp5_kms);
 
@@ -197,13 +234,33 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev,
 uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc);
 
 int mdp5_crtc_get_lm(struct drm_crtc *crtc);
+struct mdp5_ctl *mdp5_crtc_get_ctl(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_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf);
 struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
                struct drm_plane *plane, int id);
 
-struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf,
-               enum mdp5_intf intf_id);
+struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
+               struct mdp5_interface *intf);
+int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
+                                       struct drm_encoder *slave_encoder);
+
+#ifdef CONFIG_DRM_MSM_DSI
+struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
+                               struct mdp5_interface *intf);
+int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
+                                       struct drm_encoder *slave_encoder);
+#else
+static inline struct drm_encoder *mdp5_cmd_encoder_init(
+                       struct drm_device *dev, struct mdp5_interface *intf)
+{
+       return ERR_PTR(-EINVAL);
+}
+static inline int mdp5_cmd_encoder_set_split_display(
+       struct drm_encoder *encoder, struct drm_encoder *slave_encoder)
+{
+       return -EINVAL;
+}
+#endif
 
 #endif /* __MDP5_KMS_H__ */
index 6bd48e2462833e03e63a2d2967cda30db2cce8da..18a3d203b17439c2be3f0b0c72e033ed3996ae86 100644 (file)
@@ -507,8 +507,8 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
        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));
+                       MDP5_PIPE_SRC_IMG_SIZE_WIDTH(fb->width) |
+                       MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(fb->height));
 
        mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe),
                        MDP5_PIPE_SRC_SIZE_WIDTH(src_w) |
index 1f795af89680103211878ac48f77d506981395a6..16702aecf0df714e211b8d7900fc06299e0e92f8 100644 (file)
@@ -43,7 +43,7 @@
  *     set.
  *
  *  2) mdp5_smp_configure():
- *     As hw is programmed, before FLUSH, MDP5_SMP_ALLOC registers
+ *     As hw is programmed, before FLUSH, MDP5_MDP_SMP_ALLOC registers
  *     are configured for the union(pending, inuse)
  *
  *  3) mdp5_smp_commit():
@@ -74,7 +74,7 @@ struct mdp5_smp {
        spinlock_t state_lock;
        mdp5_smp_state_t state; /* to track smp allocation amongst pipes: */
 
-       struct mdp5_client_smp_state client_state[CID_MAX];
+       struct mdp5_client_smp_state client_state[MAX_CLIENTS];
 };
 
 static inline
@@ -85,27 +85,31 @@ struct mdp5_kms *get_kms(struct mdp5_smp *smp)
        return to_mdp5_kms(to_mdp_kms(priv->kms));
 }
 
-static inline enum mdp5_client_id pipe2client(enum mdp5_pipe pipe, int plane)
+static inline u32 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;
-       }
+#define CID_UNUSED     0
+
+       if (WARN_ON(plane >= pipe2nclients(pipe)))
+               return CID_UNUSED;
+
+       /*
+        * Note on SMP clients:
+        * For ViG pipes, fetch Y/Cr/Cb-components clients are always
+        * consecutive, and in that order.
+        *
+        * e.g.:
+        * if mdp5_cfg->smp.clients[SSPP_VIG0] = N,
+        *      Y  plane's client ID is N
+        *      Cr plane's client ID is N + 1
+        *      Cb plane's client ID is N + 2
+        */
+
+       return mdp5_cfg->smp.clients[pipe] + plane;
 }
 
 /* step #1: update # of blocks pending for the client: */
 static int smp_request_block(struct mdp5_smp *smp,
-               enum mdp5_client_id cid, int nblks)
+               u32 cid, int nblks)
 {
        struct mdp5_kms *mdp5_kms = get_kms(smp);
        const struct mdp5_cfg_hw *hw_cfg;
@@ -227,7 +231,7 @@ void mdp5_smp_release(struct mdp5_smp *smp, enum mdp5_pipe pipe)
 }
 
 static void update_smp_state(struct mdp5_smp *smp,
-               enum mdp5_client_id cid, mdp5_smp_state_t *assigned)
+               u32 cid, mdp5_smp_state_t *assigned)
 {
        struct mdp5_kms *mdp5_kms = get_kms(smp);
        int cnt = smp->blk_cnt;
@@ -237,25 +241,25 @@ static void update_smp_state(struct mdp5_smp *smp,
                int idx = blk / 3;
                int fld = blk % 3;
 
-               val = mdp5_read(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(idx));
+               val = mdp5_read(mdp5_kms, REG_MDP5_MDP_SMP_ALLOC_W_REG(0, idx));
 
                switch (fld) {
                case 0:
-                       val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK;
-                       val |= MDP5_SMP_ALLOC_W_REG_CLIENT0(cid);
+                       val &= ~MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__MASK;
+                       val |= MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0(cid);
                        break;
                case 1:
-                       val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK;
-                       val |= MDP5_SMP_ALLOC_W_REG_CLIENT1(cid);
+                       val &= ~MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__MASK;
+                       val |= MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1(cid);
                        break;
                case 2:
-                       val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK;
-                       val |= MDP5_SMP_ALLOC_W_REG_CLIENT2(cid);
+                       val &= ~MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__MASK;
+                       val |= MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2(cid);
                        break;
                }
 
-               mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(idx), val);
-               mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_R_REG(idx), val);
+               mdp5_write(mdp5_kms, REG_MDP5_MDP_SMP_ALLOC_W_REG(0, idx), val);
+               mdp5_write(mdp5_kms, REG_MDP5_MDP_SMP_ALLOC_R_REG(0, idx), val);
        }
 }
 
@@ -267,7 +271,7 @@ void mdp5_smp_configure(struct mdp5_smp *smp, enum mdp5_pipe pipe)
        int i;
 
        for (i = 0; i < pipe2nclients(pipe); i++) {
-               enum mdp5_client_id cid = pipe2client(pipe, i);
+               u32 cid = pipe2client(pipe, i);
                struct mdp5_client_smp_state *ps = &smp->client_state[cid];
 
                bitmap_or(assigned, ps->inuse, ps->pending, cnt);
@@ -283,7 +287,7 @@ void mdp5_smp_commit(struct mdp5_smp *smp, enum mdp5_pipe pipe)
        int i;
 
        for (i = 0; i < pipe2nclients(pipe); i++) {
-               enum mdp5_client_id cid = pipe2client(pipe, i);
+               u32 cid = pipe2client(pipe, i);
                struct mdp5_client_smp_state *ps = &smp->client_state[cid];
 
                /*
index a4269119f9eaf3eae5c2b0dbb6d37745466bd44f..47f4dd407671970fc247c4a9999dcccc03202c8e 100644 (file)
@@ -182,41 +182,57 @@ static int get_mdp_ver(struct platform_device *pdev)
        return 4;
 }
 
-static int msm_load(struct drm_device *dev, unsigned long flags)
-{
-       struct platform_device *pdev = dev->platformdev;
-       struct msm_drm_private *priv;
-       struct msm_kms *kms;
-       int ret;
-
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv) {
-               dev_err(dev->dev, "failed to allocate private data\n");
-               return -ENOMEM;
-       }
+#include <linux/of_address.h>
 
-       dev->dev_private = priv;
-
-       priv->wq = alloc_ordered_workqueue("msm", 0);
-       init_waitqueue_head(&priv->fence_event);
-       init_waitqueue_head(&priv->pending_crtcs_event);
-
-       INIT_LIST_HEAD(&priv->inactive_list);
-       INIT_LIST_HEAD(&priv->fence_cbs);
+static int msm_init_vram(struct drm_device *dev)
+{
+       struct msm_drm_private *priv = dev->dev_private;
+       unsigned long size = 0;
+       int ret = 0;
 
-       drm_mode_config_init(dev);
+#ifdef CONFIG_OF
+       /* In the device-tree world, we could have a 'memory-region'
+        * phandle, which gives us a link to our "vram".  Allocating
+        * is all nicely abstracted behind the dma api, but we need
+        * to know the entire size to allocate it all in one go. There
+        * are two cases:
+        *  1) device with no IOMMU, in which case we need exclusive
+        *     access to a VRAM carveout big enough for all gpu
+        *     buffers
+        *  2) device with IOMMU, but where the bootloader puts up
+        *     a splash screen.  In this case, the VRAM carveout
+        *     need only be large enough for fbdev fb.  But we need
+        *     exclusive access to the buffer to avoid the kernel
+        *     using those pages for other purposes (which appears
+        *     as corruption on screen before we have a chance to
+        *     load and do initial modeset)
+        */
+       struct device_node *node;
+
+       node = of_parse_phandle(dev->dev->of_node, "memory-region", 0);
+       if (node) {
+               struct resource r;
+               ret = of_address_to_resource(node, 0, &r);
+               if (ret)
+                       return ret;
+               size = r.end - r.start;
+               DRM_INFO("using VRAM carveout: %lx@%08x\n", size, r.start);
+       } else
+#endif
 
        /* if we have no IOMMU, then we need to use carveout allocator.
         * Grab the entire CMA chunk carved out in early startup in
         * mach-msm:
         */
        if (!iommu_present(&platform_bus_type)) {
+               DRM_INFO("using %s VRAM carveout\n", vram);
+               size = memparse(vram, NULL);
+       }
+
+       if (size) {
                DEFINE_DMA_ATTRS(attrs);
-               unsigned long size;
                void *p;
 
-               DBG("using %s VRAM carveout", vram);
-               size = memparse(vram, NULL);
                priv->vram.size = size;
 
                drm_mm_init(&priv->vram.mm, 0, (size >> PAGE_SHIFT) - 1);
@@ -232,8 +248,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
                if (!p) {
                        dev_err(dev->dev, "failed to allocate VRAM\n");
                        priv->vram.paddr = 0;
-                       ret = -ENOMEM;
-                       goto fail;
+                       return -ENOMEM;
                }
 
                dev_info(dev->dev, "VRAM: %08x->%08x\n",
@@ -241,6 +256,37 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
                                (uint32_t)(priv->vram.paddr + size));
        }
 
+       return ret;
+}
+
+static int msm_load(struct drm_device *dev, unsigned long flags)
+{
+       struct platform_device *pdev = dev->platformdev;
+       struct msm_drm_private *priv;
+       struct msm_kms *kms;
+       int ret;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(dev->dev, "failed to allocate private data\n");
+               return -ENOMEM;
+       }
+
+       dev->dev_private = priv;
+
+       priv->wq = alloc_ordered_workqueue("msm", 0);
+       init_waitqueue_head(&priv->fence_event);
+       init_waitqueue_head(&priv->pending_crtcs_event);
+
+       INIT_LIST_HEAD(&priv->inactive_list);
+       INIT_LIST_HEAD(&priv->fence_cbs);
+
+       drm_mode_config_init(dev);
+
+       ret = msm_init_vram(dev);
+       if (ret)
+               goto fail;
+
        platform_set_drvdata(pdev, dev);
 
        /* Bind all our sub-components: */
@@ -1030,6 +1076,7 @@ static struct platform_driver msm_platform_driver = {
 static int __init msm_drm_register(void)
 {
        DBG("init");
+       msm_dsi_register();
        msm_edp_register();
        hdmi_register();
        adreno_register();
@@ -1043,6 +1090,7 @@ static void __exit msm_drm_unregister(void)
        hdmi_unregister();
        adreno_unregister();
        msm_edp_unregister();
+       msm_dsi_unregister();
 }
 
 module_init(msm_drm_register);
index 9e8d441b61c37f2abe0f14bb16a45bda717ba3c3..04db4bd1b5b614b31905b66e56d4388938df19e1 100644 (file)
@@ -82,6 +82,9 @@ struct msm_drm_private {
         */
        struct msm_edp *edp;
 
+       /* DSI is shared by mdp4 and mdp5 */
+       struct msm_dsi *dsi[2];
+
        /* when we have more than one 'msm_gpu' these need to be an array: */
        struct msm_gpu *gpu;
        struct msm_file_private *lastctx;
@@ -236,6 +239,32 @@ void __exit msm_edp_unregister(void);
 int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev,
                struct drm_encoder *encoder);
 
+struct msm_dsi;
+enum msm_dsi_encoder_id {
+       MSM_DSI_VIDEO_ENCODER_ID = 0,
+       MSM_DSI_CMD_ENCODER_ID = 1,
+       MSM_DSI_ENCODER_NUM = 2
+};
+#ifdef CONFIG_DRM_MSM_DSI
+void __init msm_dsi_register(void);
+void __exit msm_dsi_unregister(void);
+int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
+               struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM]);
+#else
+static inline void __init msm_dsi_register(void)
+{
+}
+static inline void __exit msm_dsi_unregister(void)
+{
+}
+static inline int msm_dsi_modeset_init(struct msm_dsi *msm_dsi,
+               struct drm_device *dev,
+               struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM])
+{
+       return -EINVAL;
+}
+#endif
+
 #ifdef CONFIG_DEBUG_FS
 void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m);
 void msm_gem_describe_objects(struct list_head *list, struct seq_file *m);
index df60f65728ff7ed9b707c0e0bce25c10be1ffd61..95f6532df02d9f9ab8eb8ff7da8b64a5f24a8349 100644 (file)
@@ -110,7 +110,8 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
        size = mode_cmd.pitches[0] * mode_cmd.height;
        DBG("allocating %d bytes for fb %d", size, dev->primary->index);
        mutex_lock(&dev->struct_mutex);
-       fbdev->bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC);
+       fbdev->bo = msm_gem_new(dev, size, MSM_BO_SCANOUT |
+                       MSM_BO_WC | MSM_BO_STOLEN);
        mutex_unlock(&dev->struct_mutex);
        if (IS_ERR(fbdev->bo)) {
                ret = PTR_ERR(fbdev->bo);
index 49dea4fb55ac5fc0c6aa4efa082326a8c892e08b..479d8af72bcb77d822ea92614ea3b91601e9ac6d 100644 (file)
@@ -32,6 +32,12 @@ static dma_addr_t physaddr(struct drm_gem_object *obj)
                        priv->vram.paddr;
 }
 
+static bool use_pages(struct drm_gem_object *obj)
+{
+       struct msm_gem_object *msm_obj = to_msm_bo(obj);
+       return !msm_obj->vram_node;
+}
+
 /* allocate pages from VRAM carveout, used when no IOMMU: */
 static struct page **get_pages_vram(struct drm_gem_object *obj,
                int npages)
@@ -72,7 +78,7 @@ static struct page **get_pages(struct drm_gem_object *obj)
                struct page **p;
                int npages = obj->size >> PAGE_SHIFT;
 
-               if (iommu_present(&platform_bus_type))
+               if (use_pages(obj))
                        p = drm_gem_get_pages(obj);
                else
                        p = get_pages_vram(obj, npages);
@@ -116,7 +122,7 @@ static void put_pages(struct drm_gem_object *obj)
                sg_free_table(msm_obj->sgt);
                kfree(msm_obj->sgt);
 
-               if (iommu_present(&platform_bus_type))
+               if (use_pages(obj))
                        drm_gem_put_pages(obj, msm_obj->pages, true, false);
                else {
                        drm_mm_remove_node(msm_obj->vram_node);
@@ -580,6 +586,7 @@ static int msm_gem_new_impl(struct drm_device *dev,
        struct msm_drm_private *priv = dev->dev_private;
        struct msm_gem_object *msm_obj;
        unsigned sz;
+       bool use_vram = false;
 
        switch (flags & MSM_BO_CACHE_MASK) {
        case MSM_BO_UNCACHED:
@@ -592,15 +599,23 @@ static int msm_gem_new_impl(struct drm_device *dev,
                return -EINVAL;
        }
 
-       sz = sizeof(*msm_obj);
        if (!iommu_present(&platform_bus_type))
+               use_vram = true;
+       else if ((flags & MSM_BO_STOLEN) && priv->vram.size)
+               use_vram = true;
+
+       if (WARN_ON(use_vram && !priv->vram.size))
+               return -EINVAL;
+
+       sz = sizeof(*msm_obj);
+       if (use_vram)
                sz += sizeof(struct drm_mm_node);
 
        msm_obj = kzalloc(sz, GFP_KERNEL);
        if (!msm_obj)
                return -ENOMEM;
 
-       if (!iommu_present(&platform_bus_type))
+       if (use_vram)
                msm_obj->vram_node = (void *)&msm_obj[1];
 
        msm_obj->flags = flags;
@@ -630,7 +645,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
        if (ret)
                goto fail;
 
-       if (iommu_present(&platform_bus_type)) {
+       if (use_pages(obj)) {
                ret = drm_gem_object_init(dev, obj, size);
                if (ret)
                        goto fail;
index 8fbbd0594c46604e107d19a3fbbe59a735d2375d..85d481e29276ae63e81efbe3c08f491863a6dada 100644 (file)
@@ -21,6 +21,9 @@
 #include <linux/reservation.h>
 #include "msm_drv.h"
 
+/* Additional internal-use only BO flags: */
+#define MSM_BO_STOLEN        0x10000000    /* try to use stolen/splash memory */
+
 struct msm_gem_object {
        struct drm_gem_object base;
 
@@ -59,7 +62,7 @@ struct msm_gem_object {
        struct reservation_object _resv;
 
        /* For physically contiguous buffers.  Used when we don't have
-        * an IOMMU.
+        * an IOMMU.  Also used for stolen/splashscreen buffer.
         */
        struct drm_mm_node *vram_node;
 };
index 3a78cb48662b118c2d38859ca306565e162d8728..a9f17bdb4530e856e9f5e04e7cc7dd9029cedf81 100644 (file)
@@ -47,6 +47,10 @@ struct msm_kms_funcs {
        const struct msm_format *(*get_format)(struct msm_kms *kms, uint32_t format);
        long (*round_pixclk)(struct msm_kms *kms, unsigned long rate,
                        struct drm_encoder *encoder);
+       int (*set_split_display)(struct msm_kms *kms,
+                       struct drm_encoder *encoder,
+                       struct drm_encoder *slave_encoder,
+                       bool is_cmd_mode);
        /* cleanup: */
        void (*preclose)(struct msm_kms *kms, struct drm_file *file);
        void (*destroy)(struct msm_kms *kms);
index 542bb266a0ab8ee8f9cdfadce188d25c7605c0b4..3d96b49fe66209707acaf57bd66f6db1304e5941 100644 (file)
@@ -703,7 +703,7 @@ static void nv_crtc_prepare(struct drm_crtc *crtc)
        struct drm_device *dev = crtc->dev;
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-       struct drm_crtc_helper_funcs *funcs = crtc->helper_private;
+       const struct drm_crtc_helper_funcs *funcs = crtc->helper_private;
 
        if (nv_two_heads(dev))
                NVSetOwner(dev, nv_crtc->index);
@@ -724,7 +724,7 @@ static void nv_crtc_prepare(struct drm_crtc *crtc)
 static void nv_crtc_commit(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_crtc_helper_funcs *funcs = crtc->helper_private;
+       const struct drm_crtc_helper_funcs *funcs = crtc->helper_private;
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 
        nouveau_hw_load_state(dev, nv_crtc->index, &nv04_display(dev)->mode_reg);
index d7b495a5f30cff0100a8343ea18e7e8ea0ec404a..af7249ca0f4b18d5b5e73c2cd1137746f1b3b8a5 100644 (file)
@@ -358,7 +358,7 @@ static bool nv04_dac_mode_fixup(struct drm_encoder *encoder,
 
 static void nv04_dac_prepare(struct drm_encoder *encoder)
 {
-       struct drm_encoder_helper_funcs *helper = encoder->helper_private;
+       const struct drm_encoder_helper_funcs *helper = encoder->helper_private;
        struct drm_device *dev = encoder->dev;
        int head = nouveau_crtc(encoder->crtc)->index;
 
@@ -409,7 +409,7 @@ static void nv04_dac_commit(struct drm_encoder *encoder)
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct nouveau_drm *drm = nouveau_drm(encoder->dev);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
-       struct drm_encoder_helper_funcs *helper = encoder->helper_private;
+       const struct drm_encoder_helper_funcs *helper = encoder->helper_private;
 
        helper->dpms(encoder, DRM_MODE_DPMS_ON);
 
index f6ca343fd34a9b2db0f51258ef1c0d99b576ab0e..7cfb0cbc9b6e9f4bc24ff58f50df6995b4daa5ba 100644 (file)
@@ -244,7 +244,7 @@ static void nv04_dfp_prepare_sel_clk(struct drm_device *dev,
 static void nv04_dfp_prepare(struct drm_encoder *encoder)
 {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-       struct drm_encoder_helper_funcs *helper = encoder->helper_private;
+       const struct drm_encoder_helper_funcs *helper = encoder->helper_private;
        struct drm_device *dev = encoder->dev;
        int head = nouveau_crtc(encoder->crtc)->index;
        struct nv04_crtc_reg *crtcstate = nv04_display(dev)->mode_reg.crtc_reg;
@@ -445,7 +445,7 @@ static void nv04_dfp_commit(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
        struct nouveau_drm *drm = nouveau_drm(dev);
-       struct drm_encoder_helper_funcs *helper = encoder->helper_private;
+       const struct drm_encoder_helper_funcs *helper = encoder->helper_private;
        struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct dcb_output *dcbe = nv_encoder->dcb;
index f96237ef2a6b336dfc15da387c8059d8c751d31a..4131be5507ab7777f5ae1be803f5184d2359a320 100644 (file)
@@ -109,7 +109,7 @@ nv04_display_create(struct drm_device *dev)
                crtc->funcs->save(crtc);
 
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               struct drm_encoder_helper_funcs *func = encoder->helper_private;
+               const struct drm_encoder_helper_funcs *func = encoder->helper_private;
 
                func->save(encoder);
        }
@@ -138,7 +138,7 @@ nv04_display_destroy(struct drm_device *dev)
 
        /* Restore state */
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               struct drm_encoder_helper_funcs *func = encoder->helper_private;
+               const struct drm_encoder_helper_funcs *func = encoder->helper_private;
 
                func->restore(encoder);
        }
@@ -169,7 +169,7 @@ nv04_display_init(struct drm_device *dev)
         * on suspend too.
         */
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               struct drm_encoder_helper_funcs *func = encoder->helper_private;
+               const struct drm_encoder_helper_funcs *func = encoder->helper_private;
 
                func->restore(encoder);
        }
index d9664b37def17f01247fcbe676d7aec69f34e794..70e95cf6fd1901d6f45ce90441ea1bceb75dcaea 100644 (file)
@@ -122,7 +122,7 @@ static void nv04_tv_prepare(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
        int head = nouveau_crtc(encoder->crtc)->index;
-       struct drm_encoder_helper_funcs *helper = encoder->helper_private;
+       const struct drm_encoder_helper_funcs *helper = encoder->helper_private;
 
        helper->dpms(encoder, DRM_MODE_DPMS_OFF);
 
@@ -164,7 +164,7 @@ static void nv04_tv_commit(struct drm_encoder *encoder)
        struct drm_device *dev = encoder->dev;
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
-       struct drm_encoder_helper_funcs *helper = encoder->helper_private;
+       const struct drm_encoder_helper_funcs *helper = encoder->helper_private;
 
        helper->dpms(encoder, DRM_MODE_DPMS_ON);
 
index 731d74efc1e5714badb1ca2baaf9ff2cf67e1c7f..d9720dda838512a0c17d0310531f6d94893c784b 100644 (file)
@@ -405,7 +405,7 @@ static void nv17_tv_prepare(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
        struct nouveau_drm *drm = nouveau_drm(dev);
-       struct drm_encoder_helper_funcs *helper = encoder->helper_private;
+       const struct drm_encoder_helper_funcs *helper = encoder->helper_private;
        struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
        int head = nouveau_crtc(encoder->crtc)->index;
        uint8_t *cr_lcd = &nv04_display(dev)->mode_reg.crtc_reg[head].CRTC[
@@ -583,7 +583,7 @@ static void nv17_tv_commit(struct drm_encoder *encoder)
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-       struct drm_encoder_helper_funcs *helper = encoder->helper_private;
+       const struct drm_encoder_helper_funcs *helper = encoder->helper_private;
 
        if (get_tv_norm(encoder)->kind == TV_ENC_MODE) {
                nv17_tv_update_rescaler(encoder);
index 5ad17fc36ae30ed998aa72ca7a3a1fb399e0c56d..0b5af0fe86598c613f923b2a74e1a81e065dbd89 100644 (file)
 #define NV_DMA_TO_MEMORY                                             0x00000003
 #define NV_DMA_IN_MEMORY                                             0x0000003d
 
+#define FERMI_TWOD_A                                                 0x0000902d
+
+#define FERMI_MEMORY_TO_MEMORY_FORMAT_A                              0x0000903d
+
+#define KEPLER_INLINE_TO_MEMORY_A                                    0x0000a040
+#define KEPLER_INLINE_TO_MEMORY_B                                    0x0000a140
+
 #define NV04_DISP                                                    0x00000046
 
 #define NV03_CHANNEL_DMA                                             0x0000006b
@@ -25,6 +32,7 @@
 #define G82_CHANNEL_GPFIFO                                           0x0000826f
 #define FERMI_CHANNEL_GPFIFO                                         0x0000906f
 #define KEPLER_CHANNEL_GPFIFO_A                                      0x0000a06f
+#define MAXWELL_CHANNEL_GPFIFO_A                                     0x0000b06f
 
 #define NV50_DISP                                                    0x00005070
 #define G82_DISP                                                     0x00008270
@@ -84,6 +92,7 @@
 #define KEPLER_C                                                     0x0000a297
 
 #define MAXWELL_A                                                    0x0000b097
+#define MAXWELL_B                                                    0x0000b197
 
 #define FERMI_COMPUTE_A                                              0x000090c0
 #define FERMI_COMPUTE_B                                              0x000091c0
 #define KEPLER_COMPUTE_B                                             0x0000a1c0
 
 #define MAXWELL_COMPUTE_A                                            0x0000b0c0
+#define MAXWELL_COMPUTE_B                                            0x0000b1c0
 
 
 /*******************************************************************************
index 7e29c52617ea3714c2d27c5f3c1653149fa85652..e832f729e1b4ec4bb0e16422ef9b76c9a9b2c5b9 100644 (file)
@@ -10,4 +10,7 @@ extern struct nvkm_oclass gf100_ce1_oclass;
 extern struct nvkm_oclass gk104_ce0_oclass;
 extern struct nvkm_oclass gk104_ce1_oclass;
 extern struct nvkm_oclass gk104_ce2_oclass;
+extern struct nvkm_oclass gm204_ce0_oclass;
+extern struct nvkm_oclass gm204_ce1_oclass;
+extern struct nvkm_oclass gm204_ce2_oclass;
 #endif
index 05321ce7ab15a27c9f2154b0fbfe7a1b790f8a52..97cdeab8e44c2463c4eda905937fb721dca0d1a9 100644 (file)
@@ -116,6 +116,7 @@ extern struct nvkm_oclass *gf100_fifo_oclass;
 extern struct nvkm_oclass *gk104_fifo_oclass;
 extern struct nvkm_oclass *gk20a_fifo_oclass;
 extern struct nvkm_oclass *gk208_fifo_oclass;
+extern struct nvkm_oclass *gm204_fifo_oclass;
 
 int  nvkm_fifo_uevent_ctor(struct nvkm_object *, void *, u32,
                           struct nvkm_notify *);
index 93ef1f2bfac473401a64e60e0e0deca643cd366e..7cbe202807604673ee65bd3b8b8a115fbc6052a4 100644 (file)
@@ -38,7 +38,7 @@ nvkm_gr(void *obj)
 }
 
 #define nvkm_gr_create(p,e,c,y,d)                                        \
-       nvkm_engine_create((p), (e), (c), (y), "PGR", "graphics", (d))
+       nvkm_engine_create((p), (e), (c), (y), "PGRAPH", "graphics", (d))
 #define nvkm_gr_destroy(d)                                               \
        nvkm_engine_destroy(&(d)->base)
 #define nvkm_gr_init(d)                                                  \
@@ -72,6 +72,8 @@ extern struct nvkm_oclass *gk110_gr_oclass;
 extern struct nvkm_oclass *gk110b_gr_oclass;
 extern struct nvkm_oclass *gk208_gr_oclass;
 extern struct nvkm_oclass *gm107_gr_oclass;
+extern struct nvkm_oclass *gm204_gr_oclass;
+extern struct nvkm_oclass *gm206_gr_oclass;
 
 #include <core/enum.h>
 
index d104c1aac807f1cd37e7dbd92bf5c073c7f80106..1bcb763cfca0f7b5f8559114bd8c186ef4f15974 100644 (file)
@@ -45,4 +45,5 @@ nvkm_instmem(void *obj)
 extern struct nvkm_oclass *nv04_instmem_oclass;
 extern struct nvkm_oclass *nv40_instmem_oclass;
 extern struct nvkm_oclass *nv50_instmem_oclass;
+extern struct nvkm_oclass *gk20a_instmem_oclass;
 #endif
index 7b86acc634a090a1401196259d319db5ee4a1f04..755942352557b17bc6758633dabc37f0cae93df4 100644 (file)
@@ -35,6 +35,7 @@ extern struct nvkm_oclass *gt215_pmu_oclass;
 extern struct nvkm_oclass *gf100_pmu_oclass;
 extern struct nvkm_oclass *gf110_pmu_oclass;
 extern struct nvkm_oclass *gk104_pmu_oclass;
+extern struct nvkm_oclass *gk110_pmu_oclass;
 extern struct nvkm_oclass *gk208_pmu_oclass;
 extern struct nvkm_oclass *gk20a_pmu_oclass;
 
index 77326e344dadaf07720afb30c827d964454e7520..6edcce1658b70aa7626e7f57b38d3aa55f837685 100644 (file)
@@ -1110,6 +1110,8 @@ nouveau_bo_move_init(struct nouveau_drm *drm)
                            struct ttm_mem_reg *, struct ttm_mem_reg *);
                int (*init)(struct nouveau_channel *, u32 handle);
        } _methods[] = {
+               {  "COPY", 4, 0xb0b5, nve0_bo_move_copy, nve0_bo_move_init },
+               {  "GRCE", 0, 0xb0b5, nve0_bo_move_copy, nvc0_bo_move_init },
                {  "COPY", 4, 0xa0b5, nve0_bo_move_copy, nve0_bo_move_init },
                {  "GRCE", 0, 0xa0b5, nve0_bo_move_copy, nvc0_bo_move_init },
                { "COPY1", 5, 0x90b8, nvc0_bo_move_copy, nvc0_bo_move_init },
index e581f63cbf25eefabc64c32c6c2f7826d89aede1..0589babc506eb3ca186b31e8058dc7e86fc04f9f 100644 (file)
@@ -184,7 +184,8 @@ static int
 nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
                    u32 handle, u32 engine, struct nouveau_channel **pchan)
 {
-       static const u16 oclasses[] = { KEPLER_CHANNEL_GPFIFO_A,
+       static const u16 oclasses[] = { MAXWELL_CHANNEL_GPFIFO_A,
+                                       KEPLER_CHANNEL_GPFIFO_A,
                                        FERMI_CHANNEL_GPFIFO,
                                        G82_CHANNEL_GPFIFO,
                                        NV50_CHANNEL_GPFIFO,
index db7095ae4ebbdd7266b18c425a3864d2f035b4f6..3162040bc3148b2157249dd29f945d8d05585812 100644 (file)
@@ -309,7 +309,7 @@ detect_analog:
                nv_encoder = find_encoder(connector, DCB_OUTPUT_TV);
        if (nv_encoder && force) {
                struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
-               struct drm_encoder_helper_funcs *helper =
+               const struct drm_encoder_helper_funcs *helper =
                                                encoder->helper_private;
 
                if (helper->detect(encoder, connector) ==
@@ -592,7 +592,7 @@ nouveau_connector_set_property(struct drm_connector *connector,
 static struct drm_display_mode *
 nouveau_connector_native_mode(struct drm_connector *connector)
 {
-       struct drm_connector_helper_funcs *helper = connector->helper_private;
+       const struct drm_connector_helper_funcs *helper = connector->helper_private;
        struct nouveau_drm *drm = nouveau_drm(connector->dev);
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
        struct drm_device *dev = connector->dev;
index 860b0e2d4181da85e68abc604a5157d27fceb1b6..8670d90cdc11ed13fd3227c8d5908e971c3aaf73 100644 (file)
@@ -869,13 +869,20 @@ nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
                            struct drm_mode_create_dumb *args)
 {
        struct nouveau_bo *bo;
+       uint32_t domain;
        int ret;
 
        args->pitch = roundup(args->width * (args->bpp / 8), 256);
        args->size = args->pitch * args->height;
        args->size = roundup(args->size, PAGE_SIZE);
 
-       ret = nouveau_gem_new(dev, args->size, 0, NOUVEAU_GEM_DOMAIN_VRAM, 0, 0, &bo);
+       /* Use VRAM if there is any ; otherwise fallback to system memory */
+       if (nouveau_drm(dev)->device.info.ram_size != 0)
+               domain = NOUVEAU_GEM_DOMAIN_VRAM;
+       else
+               domain = NOUVEAU_GEM_DOMAIN_GART;
+
+       ret = nouveau_gem_new(dev, args->size, 0, domain, 0, 0, &bo);
        if (ret)
                return ret;
 
index 8763deb5188bb75ad041755e75add0b85726e106..89049335b7383a12749e3d0e2f55f00be81598d4 100644 (file)
@@ -181,6 +181,7 @@ nouveau_accel_init(struct nouveau_drm *drm)
                        break;
                case FERMI_CHANNEL_GPFIFO:
                case KEPLER_CHANNEL_GPFIFO_A:
+               case MAXWELL_CHANNEL_GPFIFO_A:
                        ret = nvc0_fence_create(drm);
                        break;
                default:
index fc68f0973f9e70f3d21fd057740379415e93c7f9..dd726523ca99315c77bf211975221f9feb69d9fb 100644 (file)
@@ -10,7 +10,7 @@
 
 #define DRIVER_MAJOR           1
 #define DRIVER_MINOR           2
-#define DRIVER_PATCHLEVEL      1
+#define DRIVER_PATCHLEVEL      2
 
 /*
  * 1.1.1:
@@ -28,6 +28,8 @@
  *     - fermi,kepler,maxwell zbc
  * 1.2.1:
  *      - allow concurrent access to bo's mapped read/write.
+ * 1.2.2:
+ *      - add NOUVEAU_GEM_DOMAIN_COHERENT flag
  */
 
 #include <nvif/client.h>
index 7c077fced1d13b84fa9a38e6680ad6174f3d2f08..0e690bf19fc9c5d04d2fdab02df59a4eeddd3a2b 100644 (file)
@@ -189,6 +189,9 @@ nouveau_gem_new(struct drm_device *dev, int size, int align, uint32_t domain,
        if (!flags || domain & NOUVEAU_GEM_DOMAIN_CPU)
                flags |= TTM_PL_FLAG_SYSTEM;
 
+       if (domain & NOUVEAU_GEM_DOMAIN_COHERENT)
+               flags |= TTM_PL_FLAG_UNCACHED;
+
        ret = nouveau_bo_new(dev, size, align, flags, tile_mode,
                             tile_flags, NULL, NULL, pnvbo);
        if (ret)
index dc5900bf54ff2117667ce0aaea5b3ef3b8516e16..775277f1edb0a4ae4c1a2862418827878710ddb8 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/of.h>
 #include <linux/reset.h>
 #include <linux/regulator/consumer.h>
+#include <linux/iommu.h>
 #include <soc/tegra/fuse.h>
 #include <soc/tegra/pmc.h>
 
@@ -91,6 +92,72 @@ static int nouveau_platform_power_down(struct nouveau_platform_gpu *gpu)
        return 0;
 }
 
+static void nouveau_platform_probe_iommu(struct device *dev,
+                                        struct nouveau_platform_gpu *gpu)
+{
+       int err;
+       unsigned long pgsize_bitmap;
+
+       mutex_init(&gpu->iommu.mutex);
+
+       if (iommu_present(&platform_bus_type)) {
+               gpu->iommu.domain = iommu_domain_alloc(&platform_bus_type);
+               if (IS_ERR(gpu->iommu.domain))
+                       goto error;
+
+               /*
+                * A IOMMU is only usable if it supports page sizes smaller
+                * or equal to the system's PAGE_SIZE, with a preference if
+                * both are equal.
+                */
+               pgsize_bitmap = gpu->iommu.domain->ops->pgsize_bitmap;
+               if (pgsize_bitmap & PAGE_SIZE) {
+                       gpu->iommu.pgshift = PAGE_SHIFT;
+               } else {
+                       gpu->iommu.pgshift = fls(pgsize_bitmap & ~PAGE_MASK);
+                       if (gpu->iommu.pgshift == 0) {
+                               dev_warn(dev, "unsupported IOMMU page size\n");
+                               goto free_domain;
+                       }
+                       gpu->iommu.pgshift -= 1;
+               }
+
+               err = iommu_attach_device(gpu->iommu.domain, dev);
+               if (err)
+                       goto free_domain;
+
+               err = nvkm_mm_init(&gpu->iommu._mm, 0,
+                                  (1ULL << 40) >> gpu->iommu.pgshift, 1);
+               if (err)
+                       goto detach_device;
+
+               gpu->iommu.mm = &gpu->iommu._mm;
+       }
+
+       return;
+
+detach_device:
+       iommu_detach_device(gpu->iommu.domain, dev);
+
+free_domain:
+       iommu_domain_free(gpu->iommu.domain);
+
+error:
+       gpu->iommu.domain = NULL;
+       gpu->iommu.pgshift = 0;
+       dev_err(dev, "cannot initialize IOMMU MM\n");
+}
+
+static void nouveau_platform_remove_iommu(struct device *dev,
+                                         struct nouveau_platform_gpu *gpu)
+{
+       if (gpu->iommu.domain) {
+               nvkm_mm_fini(&gpu->iommu._mm);
+               iommu_detach_device(gpu->iommu.domain, dev);
+               iommu_domain_free(gpu->iommu.domain);
+       }
+}
+
 static int nouveau_platform_probe(struct platform_device *pdev)
 {
        struct nouveau_platform_gpu *gpu;
@@ -118,6 +185,8 @@ static int nouveau_platform_probe(struct platform_device *pdev)
        if (IS_ERR(gpu->clk_pwr))
                return PTR_ERR(gpu->clk_pwr);
 
+       nouveau_platform_probe_iommu(&pdev->dev, gpu);
+
        err = nouveau_platform_power_up(gpu);
        if (err)
                return err;
@@ -140,10 +209,9 @@ static int nouveau_platform_probe(struct platform_device *pdev)
 err_unref:
        drm_dev_unref(drm);
 
-       return 0;
-
 power_down:
        nouveau_platform_power_down(gpu);
+       nouveau_platform_remove_iommu(&pdev->dev, gpu);
 
        return err;
 }
@@ -154,10 +222,15 @@ static int nouveau_platform_remove(struct platform_device *pdev)
        struct nouveau_drm *drm = nouveau_drm(drm_dev);
        struct nvkm_device *device = nvxx_device(&drm->device);
        struct nouveau_platform_gpu *gpu = nv_device_to_platform(device)->gpu;
+       int err;
 
        nouveau_drm_device_remove(drm_dev);
 
-       return nouveau_platform_power_down(gpu);
+       err = nouveau_platform_power_down(gpu);
+
+       nouveau_platform_remove_iommu(&pdev->dev, gpu);
+
+       return err;
 }
 
 #if IS_ENABLED(CONFIG_OF)
index 268bb72136815a2cc4bb6c9da6bf5b6a4e5d9e7e..392874cf47257b47f8e265a166851db1d25e6edd 100644 (file)
 #define __NOUVEAU_PLATFORM_H__
 
 #include "core/device.h"
+#include "core/mm.h"
 
 struct reset_control;
 struct clk;
 struct regulator;
+struct iommu_domain;
 struct platform_driver;
 
 struct nouveau_platform_gpu {
@@ -36,6 +38,22 @@ struct nouveau_platform_gpu {
        struct clk *clk_pwr;
 
        struct regulator *vdd;
+
+       struct {
+               /*
+                * Protects accesses to mm from subsystems
+                */
+               struct mutex mutex;
+
+               struct nvkm_mm _mm;
+               /*
+                * Just points to _mm. We need this to avoid embedding
+                * struct nvkm_mm in os.h
+                */
+               struct nvkm_mm *mm;
+               struct iommu_domain *domain;
+               unsigned long pgshift;
+       } iommu;
 };
 
 struct nouveau_platform_device {
index 273e50110ec3c1cd41f846b0ad1813879d159a9b..18f4497157885a897a9cbec14c390d397a02ca25 100644 (file)
@@ -82,6 +82,9 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man,
        u32 size_nc = 0;
        int ret;
 
+       if (drm->device.info.ram_size == 0)
+               return -ENOMEM;
+
        if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG)
                size_nc = 1 << nvbo->page_shift;
 
index bf429cabbaa84cdfb0880702d7c1ee5b49a1c175..a03db4368696be272602846a1bcbaf274f6559d6 100644 (file)
@@ -215,6 +215,7 @@ nv84_fence_create(struct nouveau_drm *drm)
 {
        struct nvkm_fifo *pfifo = nvxx_fifo(&drm->device);
        struct nv84_fence_priv *priv;
+       u32 domain;
        int ret;
 
        priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -231,10 +232,17 @@ nv84_fence_create(struct nouveau_drm *drm)
        priv->base.context_base = fence_context_alloc(priv->base.contexts);
        priv->base.uevent = true;
 
-       ret = nouveau_bo_new(drm->dev, 16 * priv->base.contexts, 0,
-                            TTM_PL_FLAG_VRAM, 0, 0, NULL, NULL, &priv->bo);
+       /* Use VRAM if there is any ; otherwise fallback to system memory */
+       domain = drm->device.info.ram_size != 0 ? TTM_PL_FLAG_VRAM :
+                        /*
+                         * fences created in sysmem must be non-cached or we
+                         * will lose CPU/GPU coherency!
+                         */
+                        TTM_PL_FLAG_TT | TTM_PL_FLAG_UNCACHED;
+       ret = nouveau_bo_new(drm->dev, 16 * priv->base.contexts, 0, domain, 0,
+                            0, NULL, NULL, &priv->bo);
        if (ret == 0) {
-               ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM, false);
+               ret = nouveau_bo_pin(priv->bo, domain, false);
                if (ret == 0) {
                        ret = nouveau_bo_map(priv->bo);
                        if (ret)
index 858797453e0bdc51f3b01e0c2c7d704864d09908..fa8cda7058cd5e6f67b5b7519f7eb6185cd611c7 100644 (file)
@@ -1,3 +1,4 @@
 nvkm-y += nvkm/engine/ce/gt215.o
 nvkm-y += nvkm/engine/ce/gf100.o
 nvkm-y += nvkm/engine/ce/gk104.o
+nvkm-y += nvkm/engine/ce/gm204.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c
new file mode 100644 (file)
index 0000000..577eb2e
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2015 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/ce.h>
+
+#include <core/engctx.h>
+
+struct gm204_ce_priv {
+       struct nvkm_engine base;
+};
+
+/*******************************************************************************
+ * Copy object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gm204_ce_sclass[] = {
+       { 0xb0b5, &nvkm_object_ofuncs },
+       {},
+};
+
+/*******************************************************************************
+ * PCE context
+ ******************************************************************************/
+
+static struct nvkm_ofuncs
+gm204_ce_context_ofuncs = {
+       .ctor = _nvkm_engctx_ctor,
+       .dtor = _nvkm_engctx_dtor,
+       .init = _nvkm_engctx_init,
+       .fini = _nvkm_engctx_fini,
+       .rd32 = _nvkm_engctx_rd32,
+       .wr32 = _nvkm_engctx_wr32,
+};
+
+static struct nvkm_oclass
+gm204_ce_cclass = {
+       .handle = NV_ENGCTX(CE0, 0x24),
+       .ofuncs = &gm204_ce_context_ofuncs,
+};
+
+/*******************************************************************************
+ * PCE engine/subdev functions
+ ******************************************************************************/
+
+static void
+gm204_ce_intr(struct nvkm_subdev *subdev)
+{
+       const int ce = nv_subidx(subdev) - NVDEV_ENGINE_CE0;
+       struct gm204_ce_priv *priv = (void *)subdev;
+       u32 stat = nv_rd32(priv, 0x104908 + (ce * 0x1000));
+
+       if (stat) {
+               nv_warn(priv, "unhandled intr 0x%08x\n", stat);
+               nv_wr32(priv, 0x104908 + (ce * 0x1000), stat);
+       }
+}
+
+static int
+gm204_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+              struct nvkm_oclass *oclass, void *data, u32 size,
+              struct nvkm_object **pobject)
+{
+       struct gm204_ce_priv *priv;
+       int ret;
+
+       ret = nvkm_engine_create(parent, engine, oclass, true,
+                                "PCE0", "ce0", &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       nv_subdev(priv)->unit = 0x00000040;
+       nv_subdev(priv)->intr = gm204_ce_intr;
+       nv_engine(priv)->cclass = &gm204_ce_cclass;
+       nv_engine(priv)->sclass = gm204_ce_sclass;
+       return 0;
+}
+
+static int
+gm204_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+              struct nvkm_oclass *oclass, void *data, u32 size,
+              struct nvkm_object **pobject)
+{
+       struct gm204_ce_priv *priv;
+       int ret;
+
+       ret = nvkm_engine_create(parent, engine, oclass, true,
+                                "PCE1", "ce1", &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       nv_subdev(priv)->unit = 0x00000080;
+       nv_subdev(priv)->intr = gm204_ce_intr;
+       nv_engine(priv)->cclass = &gm204_ce_cclass;
+       nv_engine(priv)->sclass = gm204_ce_sclass;
+       return 0;
+}
+
+static int
+gm204_ce2_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+              struct nvkm_oclass *oclass, void *data, u32 size,
+              struct nvkm_object **pobject)
+{
+       struct gm204_ce_priv *priv;
+       int ret;
+
+       ret = nvkm_engine_create(parent, engine, oclass, true,
+                                "PCE2", "ce2", &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       nv_subdev(priv)->unit = 0x00200000;
+       nv_subdev(priv)->intr = gm204_ce_intr;
+       nv_engine(priv)->cclass = &gm204_ce_cclass;
+       nv_engine(priv)->sclass = gm204_ce_sclass;
+       return 0;
+}
+
+struct nvkm_oclass
+gm204_ce0_oclass = {
+       .handle = NV_ENGINE(CE0, 0x24),
+       .ofuncs = &(struct nvkm_ofuncs) {
+               .ctor = gm204_ce0_ctor,
+               .dtor = _nvkm_engine_dtor,
+               .init = _nvkm_engine_init,
+               .fini = _nvkm_engine_fini,
+       },
+};
+
+struct nvkm_oclass
+gm204_ce1_oclass = {
+       .handle = NV_ENGINE(CE1, 0x24),
+       .ofuncs = &(struct nvkm_ofuncs) {
+               .ctor = gm204_ce1_ctor,
+               .dtor = _nvkm_engine_dtor,
+               .init = _nvkm_engine_init,
+               .fini = _nvkm_engine_fini,
+       },
+};
+
+struct nvkm_oclass
+gm204_ce2_oclass = {
+       .handle = NV_ENGINE(CE2, 0x24),
+       .ofuncs = &(struct nvkm_ofuncs) {
+               .ctor = gm204_ce2_ctor,
+               .dtor = _nvkm_engine_dtor,
+               .init = _nvkm_engine_init,
+               .fini = _nvkm_engine_fini,
+       },
+};
index 6efa8f38ff5472b42ec9895c7a5505c9992a50c1..63d8e52f4b226e10f913f7d694b7ff75dfc315a5 100644 (file)
@@ -139,9 +139,13 @@ nvkm_devobj_info(struct nvkm_object *object, void *data, u32 size)
 
        args->v0.chipset  = device->chipset;
        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;
+       if (pfb && pfb->ram)
+               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_size > 0)
+               args->v0.ram_user = args->v0.ram_user - imem->reserved;
+
        return 0;
 }
 
index bf5893458a477792b1da4b1100cdb022e7bebc81..6a9483f65d83a83ff8ee1b473504a96152ad05a2 100644 (file)
@@ -171,7 +171,7 @@ gk104_identify(struct nvkm_device *device)
                device->oclass[NVDEV_SUBDEV_FB     ] =  gk20a_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk20a_ibus_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] = gk20a_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &gk20a_bar_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
@@ -202,7 +202,7 @@ gk104_identify(struct nvkm_device *device)
                device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
-               device->oclass[NVDEV_SUBDEV_PMU    ] =  gf110_pmu_oclass;
+               device->oclass[NVDEV_SUBDEV_PMU    ] =  gk110_pmu_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  gk104_fifo_oclass;
@@ -236,7 +236,7 @@ gk104_identify(struct nvkm_device *device)
                device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
-               device->oclass[NVDEV_SUBDEV_PMU    ] =  gf110_pmu_oclass;
+               device->oclass[NVDEV_SUBDEV_PMU    ] =  gk110_pmu_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  gk104_fifo_oclass;
index 108d048da7643f0b97255edf06e205a72d672a48..70abf1ec7c98537212741f27a6a7e737c12a630b 100644 (file)
@@ -127,16 +127,14 @@ gm100_identify(struct nvkm_device *device)
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
 #endif
                device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
-#if 0
-               device->oclass[NVDEV_ENGINE_FIFO   ] =  gk208_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  gm204_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-               device->oclass[NVDEV_ENGINE_GR     ] =  gm107_gr_oclass;
-#endif
+               device->oclass[NVDEV_ENGINE_GR     ] =  gm204_gr_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] =  gm204_disp_oclass;
-#if 0
                device->oclass[NVDEV_ENGINE_CE0    ] = &gm204_ce0_oclass;
                device->oclass[NVDEV_ENGINE_CE1    ] = &gm204_ce1_oclass;
                device->oclass[NVDEV_ENGINE_CE2    ] = &gm204_ce2_oclass;
+#if 0
                device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
                device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
                device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
@@ -170,16 +168,14 @@ gm100_identify(struct nvkm_device *device)
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
 #endif
                device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
-#if 0
-               device->oclass[NVDEV_ENGINE_FIFO   ] =  gk208_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  gm204_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-               device->oclass[NVDEV_ENGINE_GR     ] =  gm107_gr_oclass;
-#endif
+               device->oclass[NVDEV_ENGINE_GR     ] =  gm206_gr_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] =  gm204_disp_oclass;
-#if 0
                device->oclass[NVDEV_ENGINE_CE0    ] = &gm204_ce0_oclass;
                device->oclass[NVDEV_ENGINE_CE1    ] = &gm204_ce1_oclass;
                device->oclass[NVDEV_ENGINE_CE2    ] = &gm204_ce2_oclass;
+#if 0
                device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
                device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
                device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
index 0ebf466e9ef3ea7285b30b2ad015c0bc1cc96819..9ef6728c528d999ef625a9c1472de95c0c02ba24 100644 (file)
@@ -413,8 +413,8 @@ gf110_disp_base_mthd_base = {
 
 static const struct nv50_disp_mthd_list
 gf110_disp_base_mthd_image = {
-       .mthd = 0x0400,
-       .addr = 0x000400,
+       .mthd = 0x0020,
+       .addr = 0x000020,
        .data = {
                { 0x0400, 0x661400 },
                { 0x0404, 0x661404 },
index 84ade810e27c331e057a49da0a28fe42f10062b7..8ba808df24ad2b96a0c90920dc910ceb30414ef5 100644 (file)
@@ -229,7 +229,7 @@ nv50_disp_dmac_create_(struct nvkm_object *parent,
 
                switch (dmac->pushdma->target) {
                case NV_MEM_TARGET_VRAM:
-                       dmac->push = 0x00000000 | dmac->pushdma->start >> 8;
+                       dmac->push = 0x00000001 | dmac->pushdma->start >> 8;
                        break;
                case NV_MEM_TARGET_PCI_NOSNOOP:
                        dmac->push = 0x00000003 | dmac->pushdma->start >> 8;
index c5a2d8718c5bdfdefc91e414e14d14c8d65edc79..42891cb71ea3404c211e88905d91f424f53b9d8b 100644 (file)
@@ -9,3 +9,4 @@ nvkm-y += nvkm/engine/fifo/gf100.o
 nvkm-y += nvkm/engine/fifo/gk104.o
 nvkm-y += nvkm/engine/fifo/gk20a.o
 nvkm-y += nvkm/engine/fifo/gk208.o
+nvkm-y += nvkm/engine/fifo/gm204.o
index 9585539e59f2e305b5d3d3be80d10c5fa7db38b5..e10f9644140f5d9fcd6e73446c74634d2b13906a 100644 (file)
@@ -323,8 +323,8 @@ gk104_fifo_chan_fini(struct nvkm_object *object, bool suspend)
        return nvkm_fifo_channel_fini(&chan->base, suspend);
 }
 
-static struct nvkm_ofuncs
-gk104_fifo_ofuncs = {
+struct nvkm_ofuncs
+gk104_fifo_chan_ofuncs = {
        .ctor = gk104_fifo_chan_ctor,
        .dtor = _nvkm_fifo_channel_dtor,
        .init = gk104_fifo_chan_init,
@@ -337,7 +337,7 @@ gk104_fifo_ofuncs = {
 
 static struct nvkm_oclass
 gk104_fifo_sclass[] = {
-       { KEPLER_CHANNEL_GPFIFO_A, &gk104_fifo_ofuncs },
+       { KEPLER_CHANNEL_GPFIFO_A, &gk104_fifo_chan_ofuncs },
        {}
 };
 
@@ -774,6 +774,7 @@ gk104_fifo_intr_fault(struct gk104_fifo_priv *priv, int unit)
        while (object) {
                switch (nv_mclass(object)) {
                case KEPLER_CHANNEL_GPFIFO_A:
+               case MAXWELL_CHANNEL_GPFIFO_A:
                        gk104_fifo_recover(priv, engine, (void *)object);
                        break;
                }
index 3046e00ed6ba1c41573b3e6ff415c0590043546e..318d30d6ee1aea7a8e60091e85a7667080ca99fb 100644 (file)
@@ -13,4 +13,6 @@ struct gk104_fifo_impl {
        struct nvkm_oclass base;
        u32 channels;
 };
+
+extern struct nvkm_ofuncs gk104_fifo_chan_ofuncs;
 #endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c
new file mode 100644 (file)
index 0000000..749d525
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2015 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 "gk104.h"
+
+#include <nvif/class.h>
+
+static struct nvkm_oclass
+gm204_fifo_sclass[] = {
+       { MAXWELL_CHANNEL_GPFIFO_A, &gk104_fifo_chan_ofuncs },
+       {}
+};
+
+static int
+gm204_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+               struct nvkm_oclass *oclass, void *data, u32 size,
+               struct nvkm_object **pobject)
+{
+       int ret = gk104_fifo_ctor(parent, engine, oclass, data, size, pobject);
+       if (ret == 0) {
+               struct gk104_fifo_priv *priv = (void *)*pobject;
+               nv_engine(priv)->sclass = gm204_fifo_sclass;
+       }
+       return ret;
+}
+
+struct nvkm_oclass *
+gm204_fifo_oclass = &(struct gk104_fifo_impl) {
+       .base.handle = NV_ENGINE(FIFO, 0x24),
+       .base.ofuncs = &(struct nvkm_ofuncs) {
+               .ctor = gm204_fifo_ctor,
+               .dtor = gk104_fifo_dtor,
+               .init = gk104_fifo_init,
+               .fini = _nvkm_fifo_fini,
+       },
+       .channels = 4096,
+}.base;
index 1771d944591b4d11a28d36973c700b5109271a05..2e1b92f71d9ebffb0f7322b50885d1b3b62ccb25 100644 (file)
@@ -12,6 +12,8 @@ nvkm-y += nvkm/engine/gr/ctxgk110.o
 nvkm-y += nvkm/engine/gr/ctxgk110b.o
 nvkm-y += nvkm/engine/gr/ctxgk208.o
 nvkm-y += nvkm/engine/gr/ctxgm107.o
+nvkm-y += nvkm/engine/gr/ctxgm204.o
+nvkm-y += nvkm/engine/gr/ctxgm206.o
 nvkm-y += nvkm/engine/gr/nv04.o
 nvkm-y += nvkm/engine/gr/nv10.o
 nvkm-y += nvkm/engine/gr/nv20.o
@@ -34,3 +36,5 @@ nvkm-y += nvkm/engine/gr/gk110.o
 nvkm-y += nvkm/engine/gr/gk110b.o
 nvkm-y += nvkm/engine/gr/gk208.o
 nvkm-y += nvkm/engine/gr/gm107.o
+nvkm-y += nvkm/engine/gr/gm204.o
+nvkm-y += nvkm/engine/gr/gm206.o
index 1166b1aa152559957975a34ea10563b98e8f83b8..3676a3342bc5865a673a369acc7aae6e908717a2 100644 (file)
@@ -88,11 +88,22 @@ void gk104_grctx_generate_bundle(struct gf100_grctx *);
 void gk104_grctx_generate_pagepool(struct gf100_grctx *);
 void gk104_grctx_generate_unkn(struct gf100_gr_priv *);
 void gk104_grctx_generate_r418bb8(struct gf100_gr_priv *);
+void gk104_grctx_generate_rop_active_fbps(struct gf100_gr_priv *);
+
 
 extern struct nvkm_oclass *gk110_grctx_oclass;
 extern struct nvkm_oclass *gk110b_grctx_oclass;
 extern struct nvkm_oclass *gk208_grctx_oclass;
+
 extern struct nvkm_oclass *gm107_grctx_oclass;
+void gm107_grctx_generate_bundle(struct gf100_grctx *);
+void gm107_grctx_generate_pagepool(struct gf100_grctx *);
+void gm107_grctx_generate_attrib(struct gf100_grctx *);
+
+extern struct nvkm_oclass *gm204_grctx_oclass;
+void gm204_grctx_generate_main(struct gf100_gr_priv *, struct gf100_grctx *);
+
+extern struct nvkm_oclass *gm206_grctx_oclass;
 
 /* context init value lists */
 
@@ -196,4 +207,22 @@ extern const struct gf100_gr_init gk208_grctx_init_rstr2d_0[];
 
 extern const struct gf100_gr_init gk208_grctx_init_prop_0[];
 extern const struct gf100_gr_init gk208_grctx_init_crstr_0[];
+
+extern const struct gf100_gr_init gm107_grctx_init_gpc_unk_0[];
+extern const struct gf100_gr_init gm107_grctx_init_wwdx_0[];
+
+extern const struct gf100_gr_pack gm204_grctx_pack_icmd[];
+
+extern const struct gf100_gr_pack gm204_grctx_pack_mthd[];
+
+extern const struct gf100_gr_pack gm204_grctx_pack_hub[];
+
+extern const struct gf100_gr_init gm204_grctx_init_prop_0[];
+extern const struct gf100_gr_init gm204_grctx_init_setup_0[];
+extern const struct gf100_gr_init gm204_grctx_init_gpm_0[];
+extern const struct gf100_gr_init gm204_grctx_init_gpc_unk_2[];
+
+extern const struct gf100_gr_pack gm204_grctx_pack_tpc[];
+
+extern const struct gf100_gr_pack gm204_grctx_pack_ppc[];
 #endif
index 5e9454ba158fe816e7c381e7518a259efb1565d8..b12f6a9fd9266e4c0614e3a925a8026d3890c423 100644 (file)
@@ -940,6 +940,14 @@ gk104_grctx_generate_r418bb8(struct gf100_gr_priv *priv)
                nv_wr32(priv, 0x40780c + (i * 4), data[i]);
 }
 
+void
+gk104_grctx_generate_rop_active_fbps(struct gf100_gr_priv *priv)
+{
+       const u32 fbp_count = nv_rd32(priv, 0x120074);
+       nv_mask(priv, 0x408850, 0x0000000f, fbp_count); /* zrop */
+       nv_mask(priv, 0x408958, 0x0000000f, fbp_count); /* crop */
+}
+
 void
 gk104_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info)
 {
@@ -970,13 +978,7 @@ gk104_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info)
                nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
 
        nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr);
-       if (priv->gpc_nr == 1) {
-               nv_mask(priv, 0x408850, 0x0000000f, priv->tpc_nr[0]);
-               nv_mask(priv, 0x408958, 0x0000000f, priv->tpc_nr[0]);
-       } else {
-               nv_mask(priv, 0x408850, 0x0000000f, priv->gpc_nr);
-               nv_mask(priv, 0x408958, 0x0000000f, priv->gpc_nr);
-       }
+       gk104_grctx_generate_rop_active_fbps(priv);
        nv_mask(priv, 0x419f78, 0x00000001, 0x00000000);
 
        gf100_gr_icmd(priv, oclass->icmd);
index b2fae6e389e24260bb5093ffdd9fa5d90982f277..fbeaae3ae6ce995efae4c4b26f43916ac1dcc6f0 100644 (file)
@@ -699,7 +699,7 @@ gm107_grctx_pack_hub[] = {
        {}
 };
 
-static const struct gf100_gr_init
+const struct gf100_gr_init
 gm107_grctx_init_gpc_unk_0[] = {
        { 0x418380,   1, 0x04, 0x00000056 },
        {}
@@ -834,7 +834,7 @@ gm107_grctx_init_cbm_0[] = {
        {}
 };
 
-static const struct gf100_gr_init
+const struct gf100_gr_init
 gm107_grctx_init_wwdx_0[] = {
        { 0x41bf00,   1, 0x04, 0x0a418820 },
        { 0x41bf04,   1, 0x04, 0x062080e6 },
@@ -860,7 +860,7 @@ gm107_grctx_pack_ppc[] = {
  * PGRAPH context implementation
  ******************************************************************************/
 
-static void
+void
 gm107_grctx_generate_bundle(struct gf100_grctx *info)
 {
        const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv);
@@ -877,7 +877,7 @@ gm107_grctx_generate_bundle(struct gf100_grctx *info)
        mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
 }
 
-static void
+void
 gm107_grctx_generate_pagepool(struct gf100_grctx *info)
 {
        const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv);
@@ -892,7 +892,7 @@ gm107_grctx_generate_pagepool(struct gf100_grctx *info)
        mmio_wr32(info, 0x418e30, 0x80000000); /* guess at it being related */
 }
 
-static void
+void
 gm107_grctx_generate_attrib(struct gf100_grctx *info)
 {
        struct gf100_gr_priv *priv = info->priv;
@@ -926,7 +926,7 @@ gm107_grctx_generate_attrib(struct gf100_grctx *info)
                        mmio_wr32(info, o + 0xe4, as);
                        mmio_wr32(info, o + 0xf8, ao);
                        ao += impl->alpha_nr_max * priv->ppc_tpc_nr[gpc][ppc];
-                       mmio_wr32(info, u, (0x715 /*XXX*/ << 16) | bs);
+                       mmio_wr32(info, u, ((bs / 3 /*XXX*/) << 16) | bs);
                }
        }
 }
@@ -982,13 +982,7 @@ gm107_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info)
 
        nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr);
 
-       if (priv->gpc_nr == 1) {
-               nv_mask(priv, 0x408850, 0x0000000f, priv->tpc_nr[0]);
-               nv_mask(priv, 0x408958, 0x0000000f, priv->tpc_nr[0]);
-       } else {
-               nv_mask(priv, 0x408850, 0x0000000f, priv->gpc_nr);
-               nv_mask(priv, 0x408958, 0x0000000f, priv->gpc_nr);
-       }
+       gk104_grctx_generate_rop_active_fbps(priv);
 
        gf100_gr_icmd(priv, oclass->icmd);
        nv_wr32(priv, 0x404154, 0x00000400);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c
new file mode 100644 (file)
index 0000000..ea8e661
--- /dev/null
@@ -0,0 +1,1054 @@
+/*
+ * Copyright 2015 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 "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gm204_grctx_init_icmd_0[] = {
+       { 0x001000,   1, 0x01, 0x00000002 },
+       { 0x0006aa,   1, 0x01, 0x00000001 },
+       { 0x0006ad,   2, 0x01, 0x00000100 },
+       { 0x0006b1,   1, 0x01, 0x00000011 },
+       { 0x00078c,   1, 0x01, 0x00000008 },
+       { 0x000792,   1, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
+       { 0x000797,   1, 0x01, 0x000000cf },
+       { 0x00079a,   1, 0x01, 0x00000002 },
+       { 0x0007a1,   1, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
+       { 0x000831,   1, 0x01, 0x00000004 },
+       { 0x01e100,   1, 0x01, 0x00000001 },
+       { 0x001000,   1, 0x01, 0x00000008 },
+       { 0x000039,   3, 0x01, 0x00000000 },
+       { 0x000380,   1, 0x01, 0x00000001 },
+       { 0x000366,   2, 0x01, 0x00000000 },
+       { 0x000368,   1, 0x01, 0x00000fff },
+       { 0x000370,   2, 0x01, 0x00000000 },
+       { 0x000372,   1, 0x01, 0x000fffff },
+       { 0x000374,   1, 0x01, 0x00000100 },
+       { 0x000818,   8, 0x01, 0x00000000 },
+       { 0x000848,  16, 0x01, 0x00000000 },
+       { 0x000738,   1, 0x01, 0x00000000 },
+       { 0x000b07,   1, 0x01, 0x00000002 },
+       { 0x000b08,   2, 0x01, 0x00000100 },
+       { 0x000b0a,   1, 0x01, 0x00000001 },
+       { 0x000a04,   1, 0x01, 0x000000ff },
+       { 0x000a0b,   1, 0x01, 0x00000040 },
+       { 0x00097f,   1, 0x01, 0x00000100 },
+       { 0x000a02,   1, 0x01, 0x00000001 },
+       { 0x000809,   1, 0x01, 0x00000007 },
+       { 0x00c221,   1, 0x01, 0x00000040 },
+       { 0x00c401,   1, 0x01, 0x00000001 },
+       { 0x00c402,   1, 0x01, 0x00010001 },
+       { 0x00c403,   2, 0x01, 0x00000001 },
+       { 0x00c40e,   1, 0x01, 0x00000020 },
+       { 0x01e100,   1, 0x01, 0x00000001 },
+       { 0x001000,   1, 0x01, 0x00000001 },
+       { 0x000b07,   1, 0x01, 0x00000002 },
+       { 0x000b08,   2, 0x01, 0x00000100 },
+       { 0x000b0a,   1, 0x01, 0x00000001 },
+       { 0x01e100,   1, 0x01, 0x00000001 },
+       { 0x001000,   1, 0x01, 0x00000004 },
+       { 0x000039,   3, 0x01, 0x00000000 },
+       { 0x0000a9,   1, 0x01, 0x0000ffff },
+       { 0x000038,   1, 0x01, 0x0fac6881 },
+       { 0x00003d,   1, 0x01, 0x00000001 },
+       { 0x0000e8,   8, 0x01, 0x00000400 },
+       { 0x000078,   8, 0x01, 0x00000300 },
+       { 0x000050,   1, 0x01, 0x00000011 },
+       { 0x000058,   8, 0x01, 0x00000008 },
+       { 0x000208,   8, 0x01, 0x00000001 },
+       { 0x000081,   1, 0x01, 0x00000001 },
+       { 0x000085,   1, 0x01, 0x00000004 },
+       { 0x000088,   1, 0x01, 0x00000400 },
+       { 0x000090,   1, 0x01, 0x00000300 },
+       { 0x000098,   1, 0x01, 0x00001001 },
+       { 0x0000e3,   1, 0x01, 0x00000001 },
+       { 0x0000da,   1, 0x01, 0x00000001 },
+       { 0x0000b4,   4, 0x01, 0x88888888 },
+       { 0x0000f8,   1, 0x01, 0x00000003 },
+       { 0x0000fa,   1, 0x01, 0x00000001 },
+       { 0x0000b1,   2, 0x01, 0x00000001 },
+       { 0x00009f,   4, 0x01, 0x0000ffff },
+       { 0x0000a8,   1, 0x01, 0x0000ffff },
+       { 0x0000ad,   1, 0x01, 0x0000013e },
+       { 0x0000e1,   1, 0x01, 0x00000010 },
+       { 0x000290,  16, 0x01, 0x00000000 },
+       { 0x0003b0,  16, 0x01, 0x00000000 },
+       { 0x0002a0,  16, 0x01, 0x00000000 },
+       { 0x000420,  16, 0x01, 0x00000000 },
+       { 0x0002b0,  16, 0x01, 0x00000000 },
+       { 0x000430,  16, 0x01, 0x00000000 },
+       { 0x0002c0,  16, 0x01, 0x00000000 },
+       { 0x0004d0,  16, 0x01, 0x00000000 },
+       { 0x000720,  16, 0x01, 0x00000000 },
+       { 0x0008c0,  16, 0x01, 0x00000000 },
+       { 0x000890,  16, 0x01, 0x00000000 },
+       { 0x0008e0,  16, 0x01, 0x00000000 },
+       { 0x0008a0,  16, 0x01, 0x00000000 },
+       { 0x0008f0,  16, 0x01, 0x00000000 },
+       { 0x00094c,   1, 0x01, 0x000000ff },
+       { 0x00094d,   1, 0x01, 0xffffffff },
+       { 0x00094e,   1, 0x01, 0x00000002 },
+       { 0x0002f2,   2, 0x01, 0x00000001 },
+       { 0x0002f5,   1, 0x01, 0x00000001 },
+       { 0x0002f7,   1, 0x01, 0x00000001 },
+       { 0x000303,   1, 0x01, 0x00000001 },
+       { 0x0002e6,   1, 0x01, 0x00000001 },
+       { 0x000466,   1, 0x01, 0x00000052 },
+       { 0x000301,   1, 0x01, 0x3f800000 },
+       { 0x000304,   1, 0x01, 0x30201000 },
+       { 0x000305,   1, 0x01, 0x70605040 },
+       { 0x000306,   1, 0x01, 0xb8a89888 },
+       { 0x000307,   1, 0x01, 0xf8e8d8c8 },
+       { 0x00030a,   1, 0x01, 0x00ffff00 },
+       { 0x00030b,   1, 0x01, 0x0000001a },
+       { 0x00030c,   1, 0x01, 0x00000001 },
+       { 0x000318,   1, 0x01, 0x00000001 },
+       { 0x000340,   1, 0x01, 0x00000000 },
+       { 0x00037d,   1, 0x01, 0x00000006 },
+       { 0x0003a0,   1, 0x01, 0x00000002 },
+       { 0x0003aa,   1, 0x01, 0x00000001 },
+       { 0x0003a9,   1, 0x01, 0x00000001 },
+       { 0x000380,   1, 0x01, 0x00000001 },
+       { 0x000383,   1, 0x01, 0x00000011 },
+       { 0x000360,   1, 0x01, 0x00000040 },
+       { 0x000366,   2, 0x01, 0x00000000 },
+       { 0x000368,   1, 0x01, 0x00000fff },
+       { 0x000370,   2, 0x01, 0x00000000 },
+       { 0x000372,   1, 0x01, 0x000fffff },
+       { 0x000374,   1, 0x01, 0x00000100 },
+       { 0x00037a,   1, 0x01, 0x00000012 },
+       { 0x000619,   1, 0x01, 0x00000003 },
+       { 0x000811,   1, 0x01, 0x00000003 },
+       { 0x000812,   1, 0x01, 0x00000004 },
+       { 0x000813,   1, 0x01, 0x00000006 },
+       { 0x000814,   1, 0x01, 0x00000008 },
+       { 0x000815,   1, 0x01, 0x0000000b },
+       { 0x000800,   6, 0x01, 0x00000001 },
+       { 0x000632,   1, 0x01, 0x00000001 },
+       { 0x000633,   1, 0x01, 0x00000002 },
+       { 0x000634,   1, 0x01, 0x00000003 },
+       { 0x000635,   1, 0x01, 0x00000004 },
+       { 0x000654,   1, 0x01, 0x3f800000 },
+       { 0x000657,   1, 0x01, 0x3f800000 },
+       { 0x000655,   2, 0x01, 0x3f800000 },
+       { 0x0006cd,   1, 0x01, 0x3f800000 },
+       { 0x0007f5,   1, 0x01, 0x3f800000 },
+       { 0x0007dc,   1, 0x01, 0x39291909 },
+       { 0x0007dd,   1, 0x01, 0x79695949 },
+       { 0x0007de,   1, 0x01, 0xb9a99989 },
+       { 0x0007df,   1, 0x01, 0xf9e9d9c9 },
+       { 0x0007e8,   1, 0x01, 0x00003210 },
+       { 0x0007e9,   1, 0x01, 0x00007654 },
+       { 0x0007ea,   1, 0x01, 0x00000098 },
+       { 0x0007ec,   1, 0x01, 0x39291909 },
+       { 0x0007ed,   1, 0x01, 0x79695949 },
+       { 0x0007ee,   1, 0x01, 0xb9a99989 },
+       { 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
+       { 0x0007f0,   1, 0x01, 0x00003210 },
+       { 0x0007f1,   1, 0x01, 0x00007654 },
+       { 0x0007f2,   1, 0x01, 0x00000098 },
+       { 0x0005a5,   1, 0x01, 0x00000001 },
+       { 0x0005aa,   1, 0x01, 0x00000002 },
+       { 0x0005cb,   1, 0x01, 0x00000004 },
+       { 0x0005d0,   1, 0x01, 0x20181008 },
+       { 0x0005d1,   1, 0x01, 0x40383028 },
+       { 0x0005d2,   1, 0x01, 0x60585048 },
+       { 0x0005d3,   1, 0x01, 0x80787068 },
+       { 0x000980, 128, 0x01, 0x00000000 },
+       { 0x000468,   1, 0x01, 0x00000004 },
+       { 0x00046c,   1, 0x01, 0x00000001 },
+       { 0x000470,  96, 0x01, 0x00000000 },
+       { 0x0005e0,  16, 0x01, 0x00000d10 },
+       { 0x000510,  16, 0x01, 0x3f800000 },
+       { 0x000520,   1, 0x01, 0x000002b6 },
+       { 0x000529,   1, 0x01, 0x00000001 },
+       { 0x000530,  16, 0x01, 0xffff0000 },
+       { 0x000550,  32, 0x01, 0xffff0000 },
+       { 0x000585,   1, 0x01, 0x0000003f },
+       { 0x000576,   1, 0x01, 0x00000003 },
+       { 0x00057b,   1, 0x01, 0x00000059 },
+       { 0x000586,   1, 0x01, 0x00000040 },
+       { 0x000582,   2, 0x01, 0x00000080 },
+       { 0x000595,   1, 0x01, 0x00400040 },
+       { 0x000596,   1, 0x01, 0x00000492 },
+       { 0x000597,   1, 0x01, 0x08080203 },
+       { 0x0005ad,   1, 0x01, 0x00000008 },
+       { 0x000598,   1, 0x01, 0x00020001 },
+       { 0x0005d4,   1, 0x01, 0x00000001 },
+       { 0x0005c2,   1, 0x01, 0x00000001 },
+       { 0x000638,   2, 0x01, 0x00000001 },
+       { 0x00063a,   1, 0x01, 0x00000002 },
+       { 0x00063b,   2, 0x01, 0x00000001 },
+       { 0x00063d,   1, 0x01, 0x00000002 },
+       { 0x00063e,   1, 0x01, 0x00000001 },
+       { 0x0008b8,   8, 0x01, 0x00000001 },
+       { 0x000900,   8, 0x01, 0x00000001 },
+       { 0x000908,   8, 0x01, 0x00000002 },
+       { 0x000910,  16, 0x01, 0x00000001 },
+       { 0x000920,   8, 0x01, 0x00000002 },
+       { 0x000928,   8, 0x01, 0x00000001 },
+       { 0x000662,   1, 0x01, 0x00000001 },
+       { 0x000648,   9, 0x01, 0x00000001 },
+       { 0x000674,   1, 0x01, 0x00000001 },
+       { 0x000658,   1, 0x01, 0x0000000f },
+       { 0x0007ff,   1, 0x01, 0x0000000a },
+       { 0x00066a,   1, 0x01, 0x40000000 },
+       { 0x00066b,   1, 0x01, 0x10000000 },
+       { 0x00066c,   2, 0x01, 0xffff0000 },
+       { 0x0007af,   2, 0x01, 0x00000008 },
+       { 0x0007f6,   1, 0x01, 0x00000001 },
+       { 0x0006b2,   1, 0x01, 0x00000055 },
+       { 0x0007ad,   1, 0x01, 0x00000003 },
+       { 0x000971,   1, 0x01, 0x00000008 },
+       { 0x000972,   1, 0x01, 0x00000040 },
+       { 0x000973,   1, 0x01, 0x0000012c },
+       { 0x00097c,   1, 0x01, 0x00000040 },
+       { 0x000975,   1, 0x01, 0x00000020 },
+       { 0x000976,   1, 0x01, 0x00000001 },
+       { 0x000977,   1, 0x01, 0x00000020 },
+       { 0x000978,   1, 0x01, 0x00000001 },
+       { 0x000957,   1, 0x01, 0x00000003 },
+       { 0x00095e,   1, 0x01, 0x20164010 },
+       { 0x00095f,   1, 0x01, 0x00000020 },
+       { 0x000a0d,   1, 0x01, 0x00000006 },
+       { 0x00097d,   1, 0x01, 0x0000000c },
+       { 0x000683,   1, 0x01, 0x00000006 },
+       { 0x000687,   1, 0x01, 0x003fffff },
+       { 0x0006a0,   1, 0x01, 0x00000005 },
+       { 0x000840,   1, 0x01, 0x00400008 },
+       { 0x000841,   1, 0x01, 0x08000080 },
+       { 0x000842,   1, 0x01, 0x00400008 },
+       { 0x000843,   1, 0x01, 0x08000080 },
+       { 0x000818,   8, 0x01, 0x00000000 },
+       { 0x000848,  16, 0x01, 0x00000000 },
+       { 0x000738,   1, 0x01, 0x00000000 },
+       { 0x0006aa,   1, 0x01, 0x00000001 },
+       { 0x0006ab,   1, 0x01, 0x00000002 },
+       { 0x0006ac,   1, 0x01, 0x00000080 },
+       { 0x0006ad,   2, 0x01, 0x00000100 },
+       { 0x0006b1,   1, 0x01, 0x00000011 },
+       { 0x0006bb,   1, 0x01, 0x000000cf },
+       { 0x0006ce,   1, 0x01, 0x2a712488 },
+       { 0x000739,   1, 0x01, 0x4085c000 },
+       { 0x00073a,   1, 0x01, 0x00000080 },
+       { 0x000786,   1, 0x01, 0x80000100 },
+       { 0x00073c,   1, 0x01, 0x00010100 },
+       { 0x00073d,   1, 0x01, 0x02800000 },
+       { 0x000787,   1, 0x01, 0x000000cf },
+       { 0x00078c,   1, 0x01, 0x00000008 },
+       { 0x000792,   1, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
+       { 0x000797,   1, 0x01, 0x000000cf },
+       { 0x000836,   1, 0x01, 0x00000001 },
+       { 0x00079a,   1, 0x01, 0x00000002 },
+       { 0x000833,   1, 0x01, 0x04444480 },
+       { 0x0007a1,   1, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
+       { 0x000831,   1, 0x01, 0x00000004 },
+       { 0x000b07,   1, 0x01, 0x00000002 },
+       { 0x000b08,   2, 0x01, 0x00000100 },
+       { 0x000b0a,   1, 0x01, 0x00000001 },
+       { 0x000a04,   1, 0x01, 0x000000ff },
+       { 0x000a0b,   1, 0x01, 0x00000040 },
+       { 0x00097f,   1, 0x01, 0x00000100 },
+       { 0x000a02,   1, 0x01, 0x00000001 },
+       { 0x000809,   1, 0x01, 0x00000007 },
+       { 0x00c221,   1, 0x01, 0x00000040 },
+       { 0x00c1b0,   8, 0x01, 0x0000000f },
+       { 0x00c1b8,   1, 0x01, 0x0fac6881 },
+       { 0x00c1b9,   1, 0x01, 0x00fac688 },
+       { 0x00c401,   1, 0x01, 0x00000001 },
+       { 0x00c402,   1, 0x01, 0x00010001 },
+       { 0x00c403,   2, 0x01, 0x00000001 },
+       { 0x00c40e,   1, 0x01, 0x00000020 },
+       { 0x00c413,   4, 0x01, 0x88888888 },
+       { 0x00c423,   1, 0x01, 0x0000ff00 },
+       { 0x00c420,   1, 0x01, 0x00880101 },
+       { 0x01e100,   1, 0x01, 0x00000001 },
+       {}
+};
+
+const struct gf100_gr_pack
+gm204_grctx_pack_icmd[] = {
+       { gm204_grctx_init_icmd_0 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_grctx_init_b197_0[] = {
+       { 0x000800,   8, 0x40, 0x00000000 },
+       { 0x000804,   8, 0x40, 0x00000000 },
+       { 0x000808,   8, 0x40, 0x00000400 },
+       { 0x00080c,   8, 0x40, 0x00000300 },
+       { 0x000810,   1, 0x04, 0x000000cf },
+       { 0x000850,   7, 0x40, 0x00000000 },
+       { 0x000814,   8, 0x40, 0x00000040 },
+       { 0x000818,   8, 0x40, 0x00000001 },
+       { 0x00081c,   8, 0x40, 0x00000000 },
+       { 0x000820,   8, 0x40, 0x00000000 },
+       { 0x001c00,  16, 0x10, 0x00000000 },
+       { 0x001c04,  16, 0x10, 0x00000000 },
+       { 0x001c08,  16, 0x10, 0x00000000 },
+       { 0x001c0c,  16, 0x10, 0x00000000 },
+       { 0x001d00,  16, 0x10, 0x00000000 },
+       { 0x001d04,  16, 0x10, 0x00000000 },
+       { 0x001d08,  16, 0x10, 0x00000000 },
+       { 0x001d0c,  16, 0x10, 0x00000000 },
+       { 0x001f00,  16, 0x08, 0x00000000 },
+       { 0x001f04,  16, 0x08, 0x00000000 },
+       { 0x001f80,  16, 0x08, 0x00000000 },
+       { 0x001f84,  16, 0x08, 0x00000000 },
+       { 0x002000,   1, 0x04, 0x00000000 },
+       { 0x002040,   1, 0x04, 0x00000011 },
+       { 0x002080,   1, 0x04, 0x00000020 },
+       { 0x0020c0,   1, 0x04, 0x00000030 },
+       { 0x002100,   1, 0x04, 0x00000040 },
+       { 0x002140,   1, 0x04, 0x00000051 },
+       { 0x00200c,   6, 0x40, 0x00000001 },
+       { 0x002010,   1, 0x04, 0x00000000 },
+       { 0x002050,   1, 0x04, 0x00000000 },
+       { 0x002090,   1, 0x04, 0x00000001 },
+       { 0x0020d0,   1, 0x04, 0x00000002 },
+       { 0x002110,   1, 0x04, 0x00000003 },
+       { 0x002150,   1, 0x04, 0x00000004 },
+       { 0x000380,   4, 0x20, 0x00000000 },
+       { 0x000384,   4, 0x20, 0x00000000 },
+       { 0x000388,   4, 0x20, 0x00000000 },
+       { 0x00038c,   4, 0x20, 0x00000000 },
+       { 0x000700,   4, 0x10, 0x00000000 },
+       { 0x000704,   4, 0x10, 0x00000000 },
+       { 0x000708,   4, 0x10, 0x00000000 },
+       { 0x002800, 128, 0x04, 0x00000000 },
+       { 0x000a00,  16, 0x20, 0x00000000 },
+       { 0x000a04,  16, 0x20, 0x00000000 },
+       { 0x000a08,  16, 0x20, 0x00000000 },
+       { 0x000a0c,  16, 0x20, 0x00000000 },
+       { 0x000a10,  16, 0x20, 0x00000000 },
+       { 0x000a14,  16, 0x20, 0x00000000 },
+       { 0x000a18,  16, 0x20, 0x00006420 },
+       { 0x000a1c,  16, 0x20, 0x00000000 },
+       { 0x000c00,  16, 0x10, 0x00000000 },
+       { 0x000c04,  16, 0x10, 0x00000000 },
+       { 0x000c08,  16, 0x10, 0x00000000 },
+       { 0x000c0c,  16, 0x10, 0x3f800000 },
+       { 0x000d00,   8, 0x08, 0xffff0000 },
+       { 0x000d04,   8, 0x08, 0xffff0000 },
+       { 0x000e00,  16, 0x10, 0x00000000 },
+       { 0x000e04,  16, 0x10, 0xffff0000 },
+       { 0x000e08,  16, 0x10, 0xffff0000 },
+       { 0x000d40,   4, 0x08, 0x00000000 },
+       { 0x000d44,   4, 0x08, 0x00000000 },
+       { 0x001e00,   8, 0x20, 0x00000001 },
+       { 0x001e04,   8, 0x20, 0x00000001 },
+       { 0x001e08,   8, 0x20, 0x00000002 },
+       { 0x001e0c,   8, 0x20, 0x00000001 },
+       { 0x001e10,   8, 0x20, 0x00000001 },
+       { 0x001e14,   8, 0x20, 0x00000002 },
+       { 0x001e18,   8, 0x20, 0x00000001 },
+       { 0x001480,   8, 0x10, 0x00000000 },
+       { 0x001484,   8, 0x10, 0x00000000 },
+       { 0x001488,   8, 0x10, 0x00000000 },
+       { 0x003400, 128, 0x04, 0x00000000 },
+       { 0x00030c,   1, 0x04, 0x00000001 },
+       { 0x001944,   1, 0x04, 0x00000000 },
+       { 0x001514,   1, 0x04, 0x00000000 },
+       { 0x000d68,   1, 0x04, 0x0000ffff },
+       { 0x00121c,   1, 0x04, 0x0fac6881 },
+       { 0x000fac,   1, 0x04, 0x00000001 },
+       { 0x001538,   1, 0x04, 0x00000001 },
+       { 0x000fe0,   2, 0x04, 0x00000000 },
+       { 0x000fe8,   1, 0x04, 0x00000014 },
+       { 0x000fec,   1, 0x04, 0x00000040 },
+       { 0x000ff0,   1, 0x04, 0x00000000 },
+       { 0x00179c,   1, 0x04, 0x00000000 },
+       { 0x001228,   1, 0x04, 0x00000400 },
+       { 0x00122c,   1, 0x04, 0x00000300 },
+       { 0x001230,   1, 0x04, 0x00010001 },
+       { 0x0007f8,   1, 0x04, 0x00000000 },
+       { 0x001208,   1, 0x04, 0x00000000 },
+       { 0x0015b4,   1, 0x04, 0x00000001 },
+       { 0x0015cc,   1, 0x04, 0x00000000 },
+       { 0x001534,   1, 0x04, 0x00000000 },
+       { 0x000754,   1, 0x04, 0x00000001 },
+       { 0x000fb0,   1, 0x04, 0x00000000 },
+       { 0x0015d0,   1, 0x04, 0x00000000 },
+       { 0x0011e0,   4, 0x04, 0x88888888 },
+       { 0x00153c,   1, 0x04, 0x00000000 },
+       { 0x0016b4,   1, 0x04, 0x00000003 },
+       { 0x000fa4,   1, 0x04, 0x00000001 },
+       { 0x000fbc,   4, 0x04, 0x0000ffff },
+       { 0x000fa8,   1, 0x04, 0x0000ffff },
+       { 0x000df8,   2, 0x04, 0x00000000 },
+       { 0x001948,   1, 0x04, 0x00000000 },
+       { 0x001970,   1, 0x04, 0x00000001 },
+       { 0x00161c,   1, 0x04, 0x000009f0 },
+       { 0x000dcc,   1, 0x04, 0x00000010 },
+       { 0x0015e4,   1, 0x04, 0x00000000 },
+       { 0x001160,  32, 0x04, 0x25e00040 },
+       { 0x001880,  32, 0x04, 0x00000000 },
+       { 0x000f84,   2, 0x04, 0x00000000 },
+       { 0x0017c8,   2, 0x04, 0x00000000 },
+       { 0x0017d0,   1, 0x04, 0x000000ff },
+       { 0x0017d4,   1, 0x04, 0xffffffff },
+       { 0x0017d8,   1, 0x04, 0x00000002 },
+       { 0x0017dc,   1, 0x04, 0x00000000 },
+       { 0x0015f4,   2, 0x04, 0x00000000 },
+       { 0x001434,   2, 0x04, 0x00000000 },
+       { 0x000d74,   1, 0x04, 0x00000000 },
+       { 0x0013a4,   1, 0x04, 0x00000000 },
+       { 0x001318,   1, 0x04, 0x00000001 },
+       { 0x001080,   2, 0x04, 0x00000000 },
+       { 0x001088,   2, 0x04, 0x00000001 },
+       { 0x001090,   1, 0x04, 0x00000000 },
+       { 0x001094,   1, 0x04, 0x00000001 },
+       { 0x001098,   1, 0x04, 0x00000000 },
+       { 0x00109c,   1, 0x04, 0x00000001 },
+       { 0x0010a0,   2, 0x04, 0x00000000 },
+       { 0x001644,   1, 0x04, 0x00000000 },
+       { 0x000748,   1, 0x04, 0x00000000 },
+       { 0x000de8,   1, 0x04, 0x00000000 },
+       { 0x001648,   1, 0x04, 0x00000000 },
+       { 0x0012a4,   1, 0x04, 0x00000000 },
+       { 0x001120,   4, 0x04, 0x00000000 },
+       { 0x001118,   1, 0x04, 0x00000000 },
+       { 0x00164c,   1, 0x04, 0x00000000 },
+       { 0x001658,   1, 0x04, 0x00000000 },
+       { 0x001910,   1, 0x04, 0x00000290 },
+       { 0x001518,   1, 0x04, 0x00000000 },
+       { 0x00165c,   1, 0x04, 0x00000001 },
+       { 0x001520,   1, 0x04, 0x00000000 },
+       { 0x001604,   1, 0x04, 0x00000000 },
+       { 0x001570,   1, 0x04, 0x00000000 },
+       { 0x0013b0,   2, 0x04, 0x3f800000 },
+       { 0x00020c,   1, 0x04, 0x00000000 },
+       { 0x001670,   1, 0x04, 0x30201000 },
+       { 0x001674,   1, 0x04, 0x70605040 },
+       { 0x001678,   1, 0x04, 0xb8a89888 },
+       { 0x00167c,   1, 0x04, 0xf8e8d8c8 },
+       { 0x00166c,   1, 0x04, 0x00000000 },
+       { 0x001680,   1, 0x04, 0x00ffff00 },
+       { 0x0012d0,   1, 0x04, 0x00000003 },
+       { 0x00113c,   1, 0x04, 0x00000000 },
+       { 0x0012d4,   1, 0x04, 0x00000002 },
+       { 0x001684,   2, 0x04, 0x00000000 },
+       { 0x000dac,   2, 0x04, 0x00001b02 },
+       { 0x000db4,   1, 0x04, 0x00000000 },
+       { 0x00168c,   1, 0x04, 0x00000000 },
+       { 0x0015bc,   1, 0x04, 0x00000000 },
+       { 0x00156c,   1, 0x04, 0x00000000 },
+       { 0x00187c,   1, 0x04, 0x00000000 },
+       { 0x001110,   1, 0x04, 0x00000001 },
+       { 0x000dc0,   3, 0x04, 0x00000000 },
+       { 0x000f40,   5, 0x04, 0x00000000 },
+       { 0x001234,   1, 0x04, 0x00000000 },
+       { 0x001690,   1, 0x04, 0x00000000 },
+       { 0x000790,   5, 0x04, 0x00000000 },
+       { 0x00077c,   1, 0x04, 0x00000000 },
+       { 0x001000,   1, 0x04, 0x00000010 },
+       { 0x0010fc,   1, 0x04, 0x00000000 },
+       { 0x001290,   1, 0x04, 0x00000000 },
+       { 0x000218,   1, 0x04, 0x00000010 },
+       { 0x0012d8,   1, 0x04, 0x00000000 },
+       { 0x0012dc,   1, 0x04, 0x00000010 },
+       { 0x000d94,   1, 0x04, 0x00000001 },
+       { 0x00155c,   2, 0x04, 0x00000000 },
+       { 0x001564,   1, 0x04, 0x00000fff },
+       { 0x001574,   2, 0x04, 0x00000000 },
+       { 0x00157c,   1, 0x04, 0x000fffff },
+       { 0x001354,   1, 0x04, 0x00000000 },
+       { 0x001610,   1, 0x04, 0x00000012 },
+       { 0x001608,   2, 0x04, 0x00000000 },
+       { 0x00260c,   1, 0x04, 0x00000000 },
+       { 0x0007ac,   1, 0x04, 0x00000000 },
+       { 0x00162c,   1, 0x04, 0x00000003 },
+       { 0x000210,   1, 0x04, 0x00000000 },
+       { 0x000320,   1, 0x04, 0x00000000 },
+       { 0x000324,   6, 0x04, 0x3f800000 },
+       { 0x000750,   1, 0x04, 0x00000000 },
+       { 0x000760,   1, 0x04, 0x39291909 },
+       { 0x000764,   1, 0x04, 0x79695949 },
+       { 0x000768,   1, 0x04, 0xb9a99989 },
+       { 0x00076c,   1, 0x04, 0xf9e9d9c9 },
+       { 0x000770,   1, 0x04, 0x30201000 },
+       { 0x000774,   1, 0x04, 0x70605040 },
+       { 0x000778,   1, 0x04, 0x00009080 },
+       { 0x000780,   1, 0x04, 0x39291909 },
+       { 0x000784,   1, 0x04, 0x79695949 },
+       { 0x000788,   1, 0x04, 0xb9a99989 },
+       { 0x00078c,   1, 0x04, 0xf9e9d9c9 },
+       { 0x0007d0,   1, 0x04, 0x30201000 },
+       { 0x0007d4,   1, 0x04, 0x70605040 },
+       { 0x0007d8,   1, 0x04, 0x00009080 },
+       { 0x001004,   1, 0x04, 0x00000000 },
+       { 0x001240,   8, 0x04, 0x00000000 },
+       { 0x00037c,   1, 0x04, 0x00000001 },
+       { 0x000740,   1, 0x04, 0x00000000 },
+       { 0x001148,   1, 0x04, 0x00000000 },
+       { 0x000fb4,   1, 0x04, 0x00000000 },
+       { 0x000fb8,   1, 0x04, 0x00000002 },
+       { 0x001130,   1, 0x04, 0x00000002 },
+       { 0x000fd4,   2, 0x04, 0x00000000 },
+       { 0x001030,   1, 0x04, 0x20181008 },
+       { 0x001034,   1, 0x04, 0x40383028 },
+       { 0x001038,   1, 0x04, 0x60585048 },
+       { 0x00103c,   1, 0x04, 0x80787068 },
+       { 0x000744,   1, 0x04, 0x00000000 },
+       { 0x002600,   1, 0x04, 0x00000000 },
+       { 0x001918,   1, 0x04, 0x00000000 },
+       { 0x00191c,   1, 0x04, 0x00000900 },
+       { 0x001920,   1, 0x04, 0x00000405 },
+       { 0x001308,   1, 0x04, 0x00000001 },
+       { 0x001924,   1, 0x04, 0x00000000 },
+       { 0x0013ac,   1, 0x04, 0x00000000 },
+       { 0x00192c,   1, 0x04, 0x00000001 },
+       { 0x00193c,   1, 0x04, 0x00002c1c },
+       { 0x000d7c,   1, 0x04, 0x00000000 },
+       { 0x000f8c,   1, 0x04, 0x00000000 },
+       { 0x0002c0,   1, 0x04, 0x00000001 },
+       { 0x001510,   1, 0x04, 0x00000000 },
+       { 0x001940,   1, 0x04, 0x00000000 },
+       { 0x000ff4,   2, 0x04, 0x00000000 },
+       { 0x00194c,   2, 0x04, 0x00000000 },
+       { 0x001968,   1, 0x04, 0x00000000 },
+       { 0x001590,   1, 0x04, 0x0000003f },
+       { 0x0007e8,   4, 0x04, 0x00000000 },
+       { 0x00196c,   1, 0x04, 0x00000011 },
+       { 0x0002e4,   1, 0x04, 0x0000b001 },
+       { 0x00036c,   2, 0x04, 0x00000000 },
+       { 0x00197c,   1, 0x04, 0x00000000 },
+       { 0x000fcc,   2, 0x04, 0x00000000 },
+       { 0x0002d8,   1, 0x04, 0x00000040 },
+       { 0x001980,   1, 0x04, 0x00000080 },
+       { 0x001504,   1, 0x04, 0x00000080 },
+       { 0x001984,   1, 0x04, 0x00000000 },
+       { 0x000f60,   1, 0x04, 0x00000000 },
+       { 0x000f64,   1, 0x04, 0x00400040 },
+       { 0x000f68,   1, 0x04, 0x00002212 },
+       { 0x000f6c,   1, 0x04, 0x08080203 },
+       { 0x001108,   1, 0x04, 0x00000008 },
+       { 0x000f70,   1, 0x04, 0x00080001 },
+       { 0x000ffc,   1, 0x04, 0x00000000 },
+       { 0x001134,   1, 0x04, 0x00000000 },
+       { 0x000f1c,   1, 0x04, 0x00000000 },
+       { 0x0011f8,   1, 0x04, 0x00000000 },
+       { 0x001138,   1, 0x04, 0x00000001 },
+       { 0x000300,   1, 0x04, 0x00000001 },
+       { 0x0013a8,   1, 0x04, 0x00000000 },
+       { 0x001224,   1, 0x04, 0x00000000 },
+       { 0x0012ec,   1, 0x04, 0x00000000 },
+       { 0x001310,   1, 0x04, 0x00000000 },
+       { 0x001314,   1, 0x04, 0x00000001 },
+       { 0x001380,   1, 0x04, 0x00000000 },
+       { 0x001384,   4, 0x04, 0x00000001 },
+       { 0x001394,   1, 0x04, 0x00000000 },
+       { 0x00139c,   1, 0x04, 0x00000000 },
+       { 0x001398,   1, 0x04, 0x00000000 },
+       { 0x001594,   1, 0x04, 0x00000000 },
+       { 0x001598,   4, 0x04, 0x00000001 },
+       { 0x000f54,   3, 0x04, 0x00000000 },
+       { 0x0019bc,   1, 0x04, 0x00000000 },
+       { 0x000f9c,   2, 0x04, 0x00000000 },
+       { 0x0012cc,   1, 0x04, 0x00000000 },
+       { 0x0012e8,   1, 0x04, 0x00000000 },
+       { 0x00130c,   1, 0x04, 0x00000001 },
+       { 0x001360,   8, 0x04, 0x00000000 },
+       { 0x00133c,   2, 0x04, 0x00000001 },
+       { 0x001344,   1, 0x04, 0x00000002 },
+       { 0x001348,   2, 0x04, 0x00000001 },
+       { 0x001350,   1, 0x04, 0x00000002 },
+       { 0x001358,   1, 0x04, 0x00000001 },
+       { 0x0012e4,   1, 0x04, 0x00000000 },
+       { 0x00131c,   4, 0x04, 0x00000000 },
+       { 0x0019c0,   1, 0x04, 0x00000000 },
+       { 0x001140,   1, 0x04, 0x00000000 },
+       { 0x000dd0,   1, 0x04, 0x00000000 },
+       { 0x000dd4,   1, 0x04, 0x00000001 },
+       { 0x0002f4,   1, 0x04, 0x00000000 },
+       { 0x0019c4,   1, 0x04, 0x00000000 },
+       { 0x0019c8,   1, 0x04, 0x00001500 },
+       { 0x00135c,   1, 0x04, 0x00000000 },
+       { 0x000f90,   1, 0x04, 0x00000000 },
+       { 0x0019e0,   8, 0x04, 0x00000001 },
+       { 0x0019cc,   1, 0x04, 0x00000001 },
+       { 0x00111c,   1, 0x04, 0x00000001 },
+       { 0x0015b8,   1, 0x04, 0x00000000 },
+       { 0x001a00,   1, 0x04, 0x00001111 },
+       { 0x001a04,   7, 0x04, 0x00000000 },
+       { 0x000d6c,   2, 0x04, 0xffff0000 },
+       { 0x0010f8,   1, 0x04, 0x00001010 },
+       { 0x000d80,   5, 0x04, 0x00000000 },
+       { 0x000da0,   1, 0x04, 0x00000000 },
+       { 0x0007a4,   2, 0x04, 0x00000000 },
+       { 0x001508,   1, 0x04, 0x80000000 },
+       { 0x00150c,   1, 0x04, 0x40000000 },
+       { 0x001668,   1, 0x04, 0x00000000 },
+       { 0x000318,   2, 0x04, 0x00000008 },
+       { 0x000d9c,   1, 0x04, 0x00000001 },
+       { 0x000f14,   1, 0x04, 0x00000000 },
+       { 0x000374,   1, 0x04, 0x00000000 },
+       { 0x000378,   1, 0x04, 0x0000000c },
+       { 0x0007dc,   1, 0x04, 0x00000000 },
+       { 0x00074c,   1, 0x04, 0x00000055 },
+       { 0x001420,   1, 0x04, 0x00000003 },
+       { 0x001008,   1, 0x04, 0x00000008 },
+       { 0x00100c,   1, 0x04, 0x00000040 },
+       { 0x001010,   1, 0x04, 0x0000012c },
+       { 0x000d60,   1, 0x04, 0x00000040 },
+       { 0x001018,   1, 0x04, 0x00000020 },
+       { 0x00101c,   1, 0x04, 0x00000001 },
+       { 0x001020,   1, 0x04, 0x00000020 },
+       { 0x001024,   1, 0x04, 0x00000001 },
+       { 0x001444,   3, 0x04, 0x00000000 },
+       { 0x000360,   1, 0x04, 0x20164010 },
+       { 0x000364,   1, 0x04, 0x00000020 },
+       { 0x000368,   1, 0x04, 0x00000000 },
+       { 0x000da8,   1, 0x04, 0x00000030 },
+       { 0x000de4,   1, 0x04, 0x00000000 },
+       { 0x000204,   1, 0x04, 0x00000006 },
+       { 0x0002d0,   1, 0x04, 0x003fffff },
+       { 0x001220,   1, 0x04, 0x00000005 },
+       { 0x000fdc,   1, 0x04, 0x00000000 },
+       { 0x000f98,   1, 0x04, 0x00400008 },
+       { 0x001284,   1, 0x04, 0x08000080 },
+       { 0x001450,   1, 0x04, 0x00400008 },
+       { 0x001454,   1, 0x04, 0x08000080 },
+       { 0x000214,   1, 0x04, 0x00000000 },
+       {}
+};
+
+const struct gf100_gr_pack
+gm204_grctx_pack_mthd[] = {
+       { gm204_grctx_init_b197_0, 0xb197 },
+       { gf100_grctx_init_902d_0, 0x902d },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_grctx_init_fe_0[] = {
+       { 0x404004,   8, 0x04, 0x00000000 },
+       { 0x404024,   1, 0x04, 0x0000e000 },
+       { 0x404028,   8, 0x04, 0x00000000 },
+       { 0x4040a8,   8, 0x04, 0x00000000 },
+       { 0x4040c8,   1, 0x04, 0xf801008f },
+       { 0x4040d0,   6, 0x04, 0x00000000 },
+       { 0x4040f8,   1, 0x04, 0x00000000 },
+       { 0x404100,  10, 0x04, 0x00000000 },
+       { 0x404130,   2, 0x04, 0x00000000 },
+       { 0x404150,   1, 0x04, 0x0000002e },
+       { 0x404154,   2, 0x04, 0x00000800 },
+       { 0x404164,   1, 0x04, 0x00000045 },
+       { 0x40417c,   2, 0x04, 0x00000000 },
+       { 0x404194,   1, 0x04, 0x33000700 },
+       { 0x4041a0,   4, 0x04, 0x00000000 },
+       { 0x4041c4,   2, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_grctx_init_ds_0[] = {
+       { 0x405800,   1, 0x04, 0x8f8001bf },
+       { 0x405830,   1, 0x04, 0x04001000 },
+       { 0x405834,   1, 0x04, 0x08000000 },
+       { 0x405838,   1, 0x04, 0x00010000 },
+       { 0x405854,   1, 0x04, 0x00000000 },
+       { 0x405870,   4, 0x04, 0x00000001 },
+       { 0x405a00,   2, 0x04, 0x00000000 },
+       { 0x405a18,   1, 0x04, 0x00000000 },
+       { 0x405a1c,   1, 0x04, 0x000000ff },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_grctx_init_cwd_0[] = {
+       { 0x405b00,   1, 0x04, 0x00000000 },
+       { 0x405b10,   1, 0x04, 0x00001000 },
+       { 0x405b20,   1, 0x04, 0x04000000 },
+       { 0x405b60,   6, 0x04, 0x00000000 },
+       { 0x405ba0,   6, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_grctx_init_pd_0[] = {
+       { 0x406020,   1, 0x04, 0x17410001 },
+       { 0x406028,   4, 0x04, 0x00000001 },
+       { 0x4064a8,   1, 0x04, 0x00000000 },
+       { 0x4064ac,   1, 0x04, 0x00003fff },
+       { 0x4064b0,   3, 0x04, 0x00000000 },
+       { 0x4064c0,   1, 0x04, 0x80400280 },
+       { 0x4064c4,   1, 0x04, 0x0400ffff },
+       { 0x4064c8,   1, 0x04, 0x01800780 },
+       { 0x4064cc,   9, 0x04, 0x00000000 },
+       { 0x4064fc,   1, 0x04, 0x0000022a },
+       { 0x406500,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_grctx_init_be_0[] = {
+       { 0x408800,   1, 0x04, 0x32882a3c },
+       { 0x408804,   1, 0x04, 0x00000040 },
+       { 0x408808,   1, 0x04, 0x1003e005 },
+       { 0x408840,   1, 0x04, 0x00000e0b },
+       { 0x408900,   1, 0x04, 0xb080b801 },
+       { 0x408904,   1, 0x04, 0x63038001 },
+       { 0x408908,   1, 0x04, 0x12c8502f },
+       { 0x408980,   1, 0x04, 0x0000011d },
+       {}
+};
+
+const struct gf100_gr_pack
+gm204_grctx_pack_hub[] = {
+       { gf100_grctx_init_main_0 },
+       { gm204_grctx_init_fe_0 },
+       { gk110_grctx_init_pri_0 },
+       { gk104_grctx_init_memfmt_0 },
+       { gm204_grctx_init_ds_0 },
+       { gm204_grctx_init_cwd_0 },
+       { gm204_grctx_init_pd_0 },
+       { gk208_grctx_init_rstr2d_0 },
+       { gk104_grctx_init_scc_0 },
+       { gm204_grctx_init_be_0 },
+       {}
+};
+
+const struct gf100_gr_init
+gm204_grctx_init_prop_0[] = {
+       { 0x418400,   1, 0x04, 0x38e01e00 },
+       { 0x418404,   1, 0x04, 0x70001fff },
+       { 0x41840c,   1, 0x04, 0x20001008 },
+       { 0x418410,   2, 0x04, 0x0fff0fff },
+       { 0x418418,   1, 0x04, 0x07ff07ff },
+       { 0x41841c,   1, 0x04, 0x3feffbff },
+       { 0x418450,   6, 0x04, 0x00000000 },
+       { 0x418468,   1, 0x04, 0x00000001 },
+       { 0x41846c,   2, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_grctx_init_gpc_unk_1[] = {
+       { 0x418600,   1, 0x04, 0x0000007f },
+       { 0x418684,   1, 0x04, 0x0000001f },
+       { 0x418700,   1, 0x04, 0x00000002 },
+       { 0x418704,   1, 0x04, 0x00000080 },
+       { 0x418708,   1, 0x04, 0x40000000 },
+       { 0x41870c,   2, 0x04, 0x00000000 },
+       { 0x418728,   1, 0x04, 0x00010000 },
+       {}
+};
+
+const struct gf100_gr_init
+gm204_grctx_init_setup_0[] = {
+       { 0x418800,   1, 0x04, 0x7006863a },
+       { 0x418808,   1, 0x04, 0x00000000 },
+       { 0x418810,   1, 0x04, 0x00000000 },
+       { 0x418828,   1, 0x04, 0x00000044 },
+       { 0x418830,   1, 0x04, 0x10000001 },
+       { 0x4188d8,   1, 0x04, 0x00000008 },
+       { 0x4188e0,   1, 0x04, 0x01000000 },
+       { 0x4188e8,   5, 0x04, 0x00000000 },
+       { 0x4188fc,   1, 0x04, 0x20100058 },
+       {}
+};
+
+const struct gf100_gr_init
+gm204_grctx_init_gpm_0[] = {
+       { 0x418c10,   8, 0x04, 0x00000000 },
+       { 0x418c40,   1, 0x04, 0xffffffff },
+       { 0x418c6c,   1, 0x04, 0x00000001 },
+       { 0x418c80,   1, 0x04, 0x20200000 },
+       {}
+};
+
+const struct gf100_gr_init
+gm204_grctx_init_gpc_unk_2[] = {
+       { 0x418e00,   1, 0x04, 0x90040000 },
+       { 0x418e24,   1, 0x04, 0x00000000 },
+       { 0x418e28,   1, 0x04, 0x00000030 },
+       { 0x418e2c,   1, 0x04, 0x00000100 },
+       { 0x418e30,   3, 0x04, 0x00000000 },
+       { 0x418e40,  22, 0x04, 0x00000000 },
+       { 0x418ea0,  12, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct gf100_gr_pack
+gm204_grctx_pack_gpc[] = {
+       { gm107_grctx_init_gpc_unk_0 },
+       { gm204_grctx_init_prop_0 },
+       { gm204_grctx_init_gpc_unk_1 },
+       { gm204_grctx_init_setup_0 },
+       { gf100_grctx_init_zcull_0 },
+       { gk208_grctx_init_crstr_0 },
+       { gm204_grctx_init_gpm_0 },
+       { gm204_grctx_init_gpc_unk_2 },
+       { gf100_grctx_init_gcc_0 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_grctx_init_pe_0[] = {
+       { 0x419848,   1, 0x04, 0x00000000 },
+       { 0x419864,   1, 0x04, 0x00000029 },
+       { 0x419888,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_grctx_init_tex_0[] = {
+       { 0x419a00,   1, 0x04, 0x000100f0 },
+       { 0x419a04,   1, 0x04, 0x00000005 },
+       { 0x419a08,   1, 0x04, 0x00000621 },
+       { 0x419a0c,   1, 0x04, 0x00320000 },
+       { 0x419a10,   1, 0x04, 0x00000000 },
+       { 0x419a14,   1, 0x04, 0x00000200 },
+       { 0x419a1c,   1, 0x04, 0x0010c000 },
+       { 0x419a20,   1, 0x04, 0x20008a00 },
+       { 0x419a30,   1, 0x04, 0x00000001 },
+       { 0x419a3c,   1, 0x04, 0x0000181e },
+       { 0x419ac4,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_grctx_init_mpc_0[] = {
+       { 0x419c00,   1, 0x04, 0x0000009a },
+       { 0x419c04,   1, 0x04, 0x80000bd6 },
+       { 0x419c08,   1, 0x04, 0x00000002 },
+       { 0x419c20,   1, 0x04, 0x00000000 },
+       { 0x419c24,   1, 0x04, 0x00084210 },
+       { 0x419c28,   1, 0x04, 0x3efbefbe },
+       { 0x419c2c,   1, 0x04, 0x00000000 },
+       { 0x419c34,   1, 0x04, 0x71ff1ff3 },
+       { 0x419c3c,   1, 0x04, 0x00001919 },
+       { 0x419c50,   1, 0x04, 0x00000005 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_grctx_init_l1c_0[] = {
+       { 0x419c84,   1, 0x04, 0x0000003e },
+       { 0x419c90,   1, 0x04, 0x0000000a },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_grctx_init_sm_0[] = {
+       { 0x419e04,   3, 0x04, 0x00000000 },
+       { 0x419e10,   1, 0x04, 0x00001c02 },
+       { 0x419e44,   1, 0x04, 0x00d3eff2 },
+       { 0x419e48,   1, 0x04, 0x00000000 },
+       { 0x419e4c,   1, 0x04, 0x0000007f },
+       { 0x419e50,   1, 0x04, 0x00000000 },
+       { 0x419e58,   6, 0x04, 0x00000000 },
+       { 0x419e74,  10, 0x04, 0x00000000 },
+       { 0x419eac,   1, 0x04, 0x0001cf8b },
+       { 0x419eb0,   1, 0x04, 0x00030300 },
+       { 0x419eb8,   1, 0x04, 0x40000000 },
+       { 0x419ef0,  24, 0x04, 0x00000000 },
+       { 0x419f68,   2, 0x04, 0x00000000 },
+       { 0x419f70,   1, 0x04, 0x00000020 },
+       { 0x419f78,   1, 0x04, 0x00010beb },
+       { 0x419f7c,   1, 0x04, 0x00000000 },
+       {}
+};
+
+const struct gf100_gr_pack
+gm204_grctx_pack_tpc[] = {
+       { gm204_grctx_init_pe_0 },
+       { gm204_grctx_init_tex_0 },
+       { gm204_grctx_init_mpc_0 },
+       { gm204_grctx_init_l1c_0 },
+       { gm204_grctx_init_sm_0 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_grctx_init_pes_0[] = {
+       { 0x41be24,   1, 0x04, 0x0000000e },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_grctx_init_cbm_0[] = {
+       { 0x41bec0,   1, 0x04, 0x00000000 },
+       { 0x41bec4,   1, 0x04, 0x01030000 },
+       { 0x41bee4,   1, 0x04, 0x00000000 },
+       { 0x41bef0,   1, 0x04, 0x000003ff },
+       { 0x41bef4,   2, 0x04, 0x00000000 },
+       {}
+};
+
+const struct gf100_gr_pack
+gm204_grctx_pack_ppc[] = {
+       { gm204_grctx_init_pes_0 },
+       { gm204_grctx_init_cbm_0 },
+       { gm107_grctx_init_wwdx_0 },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+static void
+gm204_grctx_generate_tpcid(struct gf100_gr_priv *priv)
+{
+       int gpc, tpc, id;
+
+       for (tpc = 0, id = 0; tpc < 4; tpc++) {
+               for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+                       if (tpc < priv->tpc_nr[gpc]) {
+                               nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id);
+                               nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
+                               nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id);
+                               id++;
+                       }
+               }
+       }
+}
+
+static void
+gm204_grctx_generate_rop_active_fbps(struct gf100_gr_priv *priv)
+{
+       const u32 fbp_count = nv_rd32(priv, 0x12006c);
+       nv_mask(priv, 0x408850, 0x0000000f, fbp_count); /* zrop */
+       nv_mask(priv, 0x408958, 0x0000000f, fbp_count); /* crop */
+}
+
+static void
+gm204_grctx_generate_405b60(struct gf100_gr_priv *priv)
+{
+       const u32 dist_nr = DIV_ROUND_UP(priv->tpc_total, 4);
+       u32 dist[TPC_MAX] = {};
+       u32 gpcs[GPC_MAX] = {};
+       u8  tpcnr[GPC_MAX];
+       int tpc, gpc, i;
+
+       memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+
+       /* won't result in the same distribution as the binary driver where
+        * some of the gpcs have more tpcs than others, but this shall do
+        * for the moment.  the code for earlier gpus has this issue too.
+        */
+       for (gpc = -1, i = 0; i < priv->tpc_total; i++) {
+               do {
+                       gpc = (gpc + 1) % priv->gpc_nr;
+               } while(!tpcnr[gpc]);
+               tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+               dist[i / 4] |= ((gpc << 4) | tpc) << ((i % 4) * 8);
+               gpcs[gpc] |= i << (tpc * 8);
+       }
+
+       for (i = 0; i < dist_nr; i++)
+               nv_wr32(priv, 0x405b60 + (i * 4), dist[i]);
+       for (i = 0; i < priv->gpc_nr; i++)
+               nv_wr32(priv, 0x405ba0 + (i * 4), gpcs[i]);
+}
+
+void
+gm204_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info)
+{
+       struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+       u32 tmp;
+       int i;
+
+       gf100_gr_mmio(priv, oclass->hub);
+       gf100_gr_mmio(priv, oclass->gpc);
+       gf100_gr_mmio(priv, oclass->zcull);
+       gf100_gr_mmio(priv, oclass->tpc);
+       gf100_gr_mmio(priv, oclass->ppc);
+
+       nv_wr32(priv, 0x404154, 0x00000000);
+
+       oclass->bundle(info);
+       oclass->pagepool(info);
+       oclass->attrib(info);
+       oclass->unkn(priv);
+
+       gm204_grctx_generate_tpcid(priv);
+       gf100_grctx_generate_r406028(priv);
+       gk104_grctx_generate_r418bb8(priv);
+
+       for (i = 0; i < 8; i++)
+               nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
+       nv_wr32(priv, 0x406500, 0x00000000);
+
+       nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr);
+
+       gm204_grctx_generate_rop_active_fbps(priv);
+
+       for (tmp = 0, i = 0; i < priv->gpc_nr; i++)
+               tmp |= ((1 << priv->tpc_nr[i]) - 1) << (i * 4);
+       nv_wr32(priv, 0x4041c4, tmp);
+
+       gm204_grctx_generate_405b60(priv);
+
+       gf100_gr_icmd(priv, oclass->icmd);
+       nv_wr32(priv, 0x404154, 0x00000800);
+       gf100_gr_mthd(priv, oclass->mthd);
+
+       nv_mask(priv, 0x418e94, 0xffffffff, 0xc4230000);
+       nv_mask(priv, 0x418e4c, 0xffffffff, 0x70000000);
+}
+
+struct nvkm_oclass *
+gm204_grctx_oclass = &(struct gf100_grctx_oclass) {
+       .base.handle = NV_ENGCTX(GR, 0x24),
+       .base.ofuncs = &(struct nvkm_ofuncs) {
+               .ctor = gf100_gr_context_ctor,
+               .dtor = gf100_gr_context_dtor,
+               .init = _nvkm_gr_context_init,
+               .fini = _nvkm_gr_context_fini,
+               .rd32 = _nvkm_gr_context_rd32,
+               .wr32 = _nvkm_gr_context_wr32,
+       },
+       .main  = gm204_grctx_generate_main,
+       .unkn  = gk104_grctx_generate_unkn,
+       .hub   = gm204_grctx_pack_hub,
+       .gpc   = gm204_grctx_pack_gpc,
+       .zcull = gf100_grctx_pack_zcull,
+       .tpc   = gm204_grctx_pack_tpc,
+       .ppc   = gm204_grctx_pack_ppc,
+       .icmd  = gm204_grctx_pack_icmd,
+       .mthd  = gm204_grctx_pack_mthd,
+       .bundle = gm107_grctx_generate_bundle,
+       .bundle_size = 0x3000,
+       .bundle_min_gpm_fifo_depth = 0x180,
+       .bundle_token_limit = 0x780,
+       .pagepool = gm107_grctx_generate_pagepool,
+       .pagepool_size = 0x20000,
+       .attrib = gm107_grctx_generate_attrib,
+       .attrib_nr_max = 0x600,
+       .attrib_nr = 0x400,
+       .alpha_nr_max = 0x1800,
+       .alpha_nr = 0x1000,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm206.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm206.c
new file mode 100644 (file)
index 0000000..91ec416
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2015 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 "ctxgf100.h"
+
+static const struct gf100_gr_init
+gm206_grctx_init_gpc_unk_1[] = {
+       { 0x418600,   1, 0x04, 0x0000007f },
+       { 0x418684,   1, 0x04, 0x0000001f },
+       { 0x418700,   1, 0x04, 0x00000002 },
+       { 0x418704,   1, 0x04, 0x00000080 },
+       { 0x418708,   1, 0x04, 0x40000000 },
+       { 0x41870c,   2, 0x04, 0x00000000 },
+       { 0x418728,   1, 0x04, 0x00300020 },
+       {}
+};
+
+static const struct gf100_gr_pack
+gm206_grctx_pack_gpc[] = {
+       { gm107_grctx_init_gpc_unk_0 },
+       { gm204_grctx_init_prop_0 },
+       { gm206_grctx_init_gpc_unk_1 },
+       { gm204_grctx_init_setup_0 },
+       { gf100_grctx_init_zcull_0 },
+       { gk208_grctx_init_crstr_0 },
+       { gm204_grctx_init_gpm_0 },
+       { gm204_grctx_init_gpc_unk_2 },
+       { gf100_grctx_init_gcc_0 },
+       {}
+};
+
+struct nvkm_oclass *
+gm206_grctx_oclass = &(struct gf100_grctx_oclass) {
+       .base.handle = NV_ENGCTX(GR, 0x26),
+       .base.ofuncs = &(struct nvkm_ofuncs) {
+               .ctor = gf100_gr_context_ctor,
+               .dtor = gf100_gr_context_dtor,
+               .init = _nvkm_gr_context_init,
+               .fini = _nvkm_gr_context_fini,
+               .rd32 = _nvkm_gr_context_rd32,
+               .wr32 = _nvkm_gr_context_wr32,
+       },
+       .main  = gm204_grctx_generate_main,
+       .unkn  = gk104_grctx_generate_unkn,
+       .hub   = gm204_grctx_pack_hub,
+       .gpc   = gm206_grctx_pack_gpc,
+       .zcull = gf100_grctx_pack_zcull,
+       .tpc   = gm204_grctx_pack_tpc,
+       .ppc   = gm204_grctx_pack_ppc,
+       .icmd  = gm204_grctx_pack_icmd,
+       .mthd  = gm204_grctx_pack_mthd,
+       .bundle = gm107_grctx_generate_bundle,
+       .bundle_size = 0x3000,
+       .bundle_min_gpm_fifo_depth = 0x180,
+       .bundle_token_limit = 0x780,
+       .pagepool = gm107_grctx_generate_pagepool,
+       .pagepool_size = 0x20000,
+       .attrib = gm107_grctx_generate_attrib,
+       .attrib_nr_max = 0x600,
+       .attrib_nr = 0x400,
+       .alpha_nr_max = 0x1800,
+       .alpha_nr = 0x1000,
+}.base;
index eaed1599b90f6f6acc1aeec6d436a0592146b1ac..194afe910d212885d01771a0355e4e8b009ab871 100644 (file)
@@ -52,6 +52,12 @@ mmio_list_base:
 #endif
 
 #ifdef INCLUDE_CODE
+#define gpc_wr32(addr,reg)                                                    /*
+*/     mov b32 $r15 reg                                                      /*
+*/     imm32($r14, addr)                                                     /*
+*/     or $r14 NV_PGRAPH_GPCX_GPCCS_MMIO_CTRL_BASE_ENABLE                    /*
+*/     call(nv_wr32)
+
 // reports an exception to the host
 //
 // In: $r15 error code (see os.h)
@@ -64,6 +70,43 @@ error:
        pop $r14
        ret
 
+#if CHIPSET >= GM107
+tpc_strand_wait:
+       push $r9
+       trace_set(T_STRTPC)
+       tpc_strand_busy:
+               nv_iord($r9, NV_PGRAPH_GPCX_GPCCS_TPC_STATUS, 0)
+               bra b32 $r9 0x0 ne #tpc_strand_busy
+       trace_clr(T_STRTPC)
+       pop $r9
+       ret
+
+#define tpc_strand_wait() call(tpc_strand_wait)
+#define tpc_strand_enable()                                                   /*
+*/     mov $r15 NV_PGRAPH_GPC0_TPCX_STRAND_CMD_ENABLE                        /*
+*/     gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_CMD, $r15)                        /*
+*/     tpc_strand_wait()
+#define tpc_strand_disable()                                                  /*
+*/     mov $r15 NV_PGRAPH_GPC0_TPCX_STRAND_CMD_DISABLE                       /*
+*/     gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_CMD, $r15)                        /*
+*/     tpc_strand_wait()
+#define tpc_strand_seek(p)                                                    /*
+*/     mov $r15 NV_PGRAPH_GPC0_TPCX_STRAND_INDEX_ALL                         /*
+*/     gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_INDEX, $r15)                      /*
+*/     mov $r15 p                                                            /*
+*/     gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_SELECT, $r15)                     /*
+*/     mov $r15 NV_PGRAPH_GPC0_TPCX_STRAND_CMD_SEEK                          /*
+*/     tpc_strand_wait()
+#define tpc_strand_info(m)                                                    /*
+*/     gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_CMD, $r15)                        /*
+*/     mov $r15 m                                                            /*
+*/     gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_DATA, $r15)                       /*
+*/     mov $r15 NV_PGRAPH_GPC0_TPCX_STRAND_CMD_GET_INFO                      /*
+*/     gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_CMD, $r15)                        /*
+*/     tpc_strand_wait()
+#endif
+
+
 // GPC fuc initialisation, executed by triggering ucode start, will
 // fall through to main loop after completion.
 //
@@ -101,7 +144,7 @@ init:
        // enable interrupts
        bset $flags ie0
 
-       // figure out which GPC we are, and how many TPCs we have
+       // how many TPCs do we have?
        nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_UNITS, 0)
        mov $r3 1
        and $r2 0x1f
@@ -109,8 +152,12 @@ init:
        sub b32 $r3 1
        st b32 D[$r0 + #tpc_count] $r2
        st b32 D[$r0 + #tpc_mask] $r3
+
+       // determine which GPC we are, setup (optional) mmio access offset
        nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_MYINDEX, 0)
        st b32 D[$r0 + #gpc_id] $r2
+       shl b32 $r2 15
+       nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMIO_BASE, 0, $r2)
 
 #if NV_PGRAPH_GPCX_UNK__SIZE > 0
        // figure out which, and how many, UNKs are actually present
@@ -186,8 +233,56 @@ init:
        // calculate size of strand context data
        mov b32 $r15 $r2
        call(strand_ctx_init)
+       add b32 $r2 $r15
        add b32 $r3 $r15
 
+#if CHIPSET >= GM107
+       // calculate size of tpc strand context data
+       mov $r15 NV_PGRAPH_GPC0_TPCX_STRAND_INDEX_ALL
+       gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_INDEX, $r15)
+       tpc_strand_enable();
+       tpc_strand_seek(0);
+       tpc_strand_info(-1);
+
+       ld b32 $r4 D[$r0 + #tpc_count]
+       mov $r5 NV_PGRAPH_GPC0_TPC0
+       ld b32 $r6 D[$r0 + #gpc_id]
+       shl b32 $r6 15
+       add b32 $r5 $r6
+       tpc_strand_init_tpc_loop:
+               add b32 $r14 $r5 NV_TPC_STRAND_CNT
+               call(nv_rd32)
+               mov b32 $r6 $r15
+               clear b32 $r7
+               tpc_strand_init_idx_loop:
+                       add b32 $r14 $r5 NV_TPC_STRAND_INDEX
+                       mov b32 $r15 $r7
+                       call(nv_wr32)
+                       add b32 $r14 $r5 NV_TPC_STRAND_SAVE_SWBASE
+                       shr b32 $r15 $r2 8
+                       call(nv_wr32)
+                       add b32 $r14 $r5 NV_TPC_STRAND_LOAD_SWBASE
+                       shr b32 $r15 $r2 8
+                       call(nv_wr32)
+                       add b32 $r14 $r5 NV_TPC_STRAND_WORDS
+                       call(nv_rd32)
+                       shr b32 $r15 6
+                       add b32 $r15 1
+                       shl b32 $r15 8
+                       add b32 $r2 $r15
+                       add b32 $r3 $r15
+                       add b32 $r7 1
+                       sub b32 $r6 1
+                       bra nz #tpc_strand_init_idx_loop
+               add b32 $r5 NV_PGRAPH_GPC0_TPC0__SIZE
+               sub b32 $r4 1
+               bra nz #tpc_strand_init_tpc_loop
+
+       mov $r15 NV_PGRAPH_GPC0_TPCX_STRAND_INDEX_ALL
+       gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_INDEX, $r15)
+       tpc_strand_disable();
+#endif
+
        // save context size, and tell HUB we're done
        nv_iowr(NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(1), 0, $r3)
        clear b32 $r2
@@ -306,6 +401,9 @@ ctx_redswitch:
 ctx_xfer:
        // set context base address
        nv_iowr(NV_PGRAPH_GPCX_GPCCS_MEM_BASE, 0, $r15)
+#if CHIPSET >= GM107
+       gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_MEM_BASE, $r15)
+#endif
        bra not $p1 #ctx_xfer_not_load
                call(ctx_redswitch)
        ctx_xfer_not_load:
@@ -318,6 +416,14 @@ ctx_xfer:
        add b32 $r2 NV_PGRAPH_GPCX_GPCCS_STRAND_CMD_SAVE
        nv_iowr(NV_PGRAPH_GPCX_GPCCS_STRAND_CMD, 0x3f, $r2)
 
+#if CHIPSET >= GM107
+       tpc_strand_enable();
+       tpc_strand_seek(0);
+       xbit $r15 $flags $p1    // SAVE/LOAD
+       add b32 $r15 NV_PGRAPH_GPC0_TPCX_STRAND_CMD_SAVE
+       gpc_wr32(NV_PGRAPH_GPC0_TPCX_STRAND_CMD, $r15)
+#endif
+
        // mmio context
        xbit $r10 $flags $p1    // direction
        or $r10 2               // first
@@ -362,6 +468,9 @@ ctx_xfer:
 
        // wait for strands to finish
        call(strand_wait)
+#if CHIPSET >= GM107
+       tpc_strand_wait()
+#endif
 
        // if load, or a save without a load following, do some
        // unknown stuff that's done after finishing a block of
@@ -370,6 +479,9 @@ ctx_xfer:
        bra not $p2 #ctx_xfer_done
        ctx_xfer_post:
                call(strand_post)
+#if CHIPSET >= GM107
+               tpc_strand_disable()
+#endif
 
        // mark completion in HUB's barrier
        ctx_xfer_done:
index ea32f56c0a92cd05c128ca2af156c0ca95e73add..231f696d1e0acd081dfde70d3d15a80632498755 100644 (file)
@@ -310,7 +310,7 @@ uint32_t gf100_grgpc_code[] = {
        0x03f01200,
        0x0002d000,
        0x17f104bd,
-       0x10fe04e6,
+       0x10fe04f8,
        0x0007f100,
        0x0003f007,
        0xbd0000d0,
@@ -329,157 +329,157 @@ uint32_t gf100_grgpc_code[] = {
        0xf0860027,
        0x22cf0123,
        0x04028000,
-       0x010027f1,
-       0xcf0223f0,
-       0x34bd0022,
-       0xf1082595,
-       0xf0c00007,
-       0x05d00103,
+       0xf10f24b6,
+       0xf0c90007,
+       0x02d00103,
        0xf104bd00,
-       0xf0c10007,
-       0x05d00103,
-       0x9804bd00,
-       0x0f98000e,
-       0x5021f501,
-       0x002fbb01,
-       0x98003fbb,
-       0x0f98010e,
-       0x5021f502,
-       0x050e9801,
-       0xbb00effd,
-       0x3ebb002e,
-       0x0235b600,
-       0xd30007f1,
-       0xd00103f0,
-       0x04bd0003,
-       0xb60825b6,
-       0x20b60635,
-       0x0130b601,
-       0xb60824b6,
-       0x2fb90834,
-       0xd321f502,
-       0x003fbb02,
-       0x010007f1,
+       0xf0010027,
+       0x22cf0223,
+       0x9534bd00,
+       0x07f10825,
+       0x03f0c000,
+       0x0005d001,
+       0x07f104bd,
+       0x03f0c100,
+       0x0005d001,
+       0x0e9804bd,
+       0x010f9800,
+       0x015021f5,
+       0xbb002fbb,
+       0x0e98003f,
+       0x020f9801,
+       0x015021f5,
+       0xfd050e98,
+       0x2ebb00ef,
+       0x003ebb00,
+       0xf10235b6,
+       0xf0d30007,
+       0x03d00103,
+       0xb604bd00,
+       0x35b60825,
+       0x0120b606,
+       0xb60130b6,
+       0x34b60824,
+       0x022fb908,
+       0x02d321f5,
+       0xbb002fbb,
+       0x07f1003f,
+       0x03f00100,
+       0x0003d002,
+       0x24bd04bd,
+       0xf11f29f0,
+       0xf0080007,
+       0x02d00203,
+/* 0x04bb: main */
+       0xf404bd00,
+       0x28f40031,
+       0x1cd7f000,
+       0xf43921f4,
+       0xe4b0f401,
+       0x1e18f404,
+       0xf00181fe,
+       0x20bd0627,
+       0xb60412fd,
+       0x1efd01e4,
+       0x0018fe05,
+       0x05b021f5,
+/* 0x04eb: main_not_ctx_xfer */
+       0x94d30ef4,
+       0xf5f010ef,
+       0x7e21f501,
+       0xc60ef403,
+/* 0x04f8: ih */
+       0x88fe80f9,
+       0xf980f901,
+       0xf9a0f990,
+       0xf9d0f9b0,
+       0xbdf0f9e0,
+       0x00a7f104,
+       0x00a3f002,
+       0xc400aacf,
+       0x0bf404ab,
+       0x1cd7f02c,
+       0x1a00e7f1,
+       0xcf00e3f0,
+       0xf7f100ee,
+       0xf3f01900,
+       0x00ffcf00,
+       0xf00421f4,
+       0x07f101e7,
+       0x03f01d00,
+       0x000ed000,
+/* 0x0546: ih_no_fifo */
+       0x07f104bd,
+       0x03f00100,
+       0x000ad000,
+       0xf0fc04bd,
+       0xd0fce0fc,
+       0xa0fcb0fc,
+       0x80fc90fc,
+       0xfc0088fe,
+       0x0032f480,
+/* 0x056a: hub_barrier_done */
+       0xf7f001f8,
+       0x040e9801,
+       0xb904febb,
+       0xe7f102ff,
+       0xe3f09418,
+       0x9d21f440,
+/* 0x0582: ctx_redswitch */
+       0xf7f000f8,
+       0x0007f120,
+       0x0103f085,
+       0xbd000fd0,
+       0x08e7f004,
+/* 0x0594: ctx_redswitch_delay */
+       0xf401e2b6,
+       0xf5f1fd1b,
+       0xf5f10800,
+       0x07f10200,
+       0x03f08500,
+       0x000fd001,
+       0x00f804bd,
+/* 0x05b0: ctx_xfer */
+       0x810007f1,
        0xd00203f0,
-       0x04bd0003,
-       0x29f024bd,
-       0x0007f11f,
-       0x0203f008,
-       0xbd0002d0,
-/* 0x04a9: main */
-       0x0031f404,
-       0xf00028f4,
-       0x21f41cd7,
-       0xf401f439,
-       0xf404e4b0,
-       0x81fe1e18,
-       0x0627f001,
-       0x12fd20bd,
-       0x01e4b604,
-       0xfe051efd,
-       0x21f50018,
-       0x0ef4059e,
-/* 0x04d9: main_not_ctx_xfer */
-       0x10ef94d3,
-       0xf501f5f0,
-       0xf4037e21,
-/* 0x04e6: ih */
-       0x80f9c60e,
-       0xf90188fe,
-       0xf990f980,
-       0xf9b0f9a0,
-       0xf9e0f9d0,
-       0xf104bdf0,
-       0xf00200a7,
-       0xaacf00a3,
-       0x04abc400,
-       0xf02c0bf4,
-       0xe7f11cd7,
-       0xe3f01a00,
-       0x00eecf00,
-       0x1900f7f1,
-       0xcf00f3f0,
-       0x21f400ff,
-       0x01e7f004,
-       0x1d0007f1,
-       0xd00003f0,
-       0x04bd000e,
-/* 0x0534: ih_no_fifo */
-       0x010007f1,
-       0xd00003f0,
-       0x04bd000a,
-       0xe0fcf0fc,
-       0xb0fcd0fc,
-       0x90fca0fc,
-       0x88fe80fc,
-       0xf480fc00,
-       0x01f80032,
-/* 0x0558: hub_barrier_done */
-       0x9801f7f0,
-       0xfebb040e,
-       0x02ffb904,
-       0x9418e7f1,
-       0xf440e3f0,
-       0x00f89d21,
-/* 0x0570: ctx_redswitch */
-       0xf120f7f0,
-       0xf0850007,
-       0x0fd00103,
-       0xf004bd00,
-/* 0x0582: ctx_redswitch_delay */
-       0xe2b608e7,
-       0xfd1bf401,
-       0x0800f5f1,
-       0x0200f5f1,
-       0x850007f1,
-       0xd00103f0,
        0x04bd000f,
-/* 0x059e: ctx_xfer */
-       0x07f100f8,
-       0x03f08100,
-       0x000fd002,
-       0x11f404bd,
-       0x7021f507,
-/* 0x05b1: ctx_xfer_not_load */
-       0x6a21f505,
-       0xf124bd02,
-       0xf047fc07,
+       0xf50711f4,
+/* 0x05c3: ctx_xfer_not_load */
+       0xf5058221,
+       0xbd026a21,
+       0xfc07f124,
+       0x0203f047,
+       0xbd0002d0,
+       0x012cf004,
+       0xf10320b6,
+       0xf04afc07,
        0x02d00203,
        0xf004bd00,
-       0x20b6012c,
-       0xfc07f103,
-       0x0203f04a,
-       0xbd0002d0,
-       0x01acf004,
-       0xf102a5f0,
-       0xf00000b7,
-       0x0c9850b3,
-       0x0fc4b604,
-       0x9800bcbb,
-       0x0d98000c,
-       0x00e7f001,
-       0x016f21f5,
-       0xf001acf0,
-       0xb7f104a5,
-       0xb3f04000,
-       0x040c9850,
-       0xbb0fc4b6,
-       0x0c9800bc,
-       0x020d9801,
-       0xf1060f98,
-       0xf50800e7,
-       0xf5016f21,
-       0xf4025e21,
-       0x12f40601,
-/* 0x0629: ctx_xfer_post */
-       0x7f21f507,
-/* 0x062d: ctx_xfer_done */
-       0x5821f502,
-       0x0000f805,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+       0xa5f001ac,
+       0x00b7f102,
+       0x50b3f000,
+       0xb6040c98,
+       0xbcbb0fc4,
+       0x000c9800,
+       0xf0010d98,
+       0x21f500e7,
+       0xacf0016f,
+       0x04a5f001,
+       0x4000b7f1,
+       0x9850b3f0,
+       0xc4b6040c,
+       0x00bcbb0f,
+       0x98010c98,
+       0x0f98020d,
+       0x00e7f106,
+       0x6f21f508,
+       0x5e21f501,
+       0x0601f402,
+/* 0x063b: ctx_xfer_post */
+       0xf50712f4,
+/* 0x063f: ctx_xfer_done */
+       0xf5027f21,
+       0xf8056a21,
        0x00000000,
        0x00000000,
        0x00000000,
index 9a36d9cbb8a5822696c4ca4b865c8372497f6d12..64d07df4b8b14e3dd805948a783c41751adb8964 100644 (file)
@@ -314,7 +314,7 @@ uint32_t gf117_grgpc_code[] = {
        0x03f01200,
        0x0002d000,
        0x17f104bd,
-       0x10fe0530,
+       0x10fe0542,
        0x0007f100,
        0x0003f007,
        0xbd0000d0,
@@ -333,188 +333,188 @@ uint32_t gf117_grgpc_code[] = {
        0xf0860027,
        0x22cf0123,
        0x04028000,
-       0x0c30e7f1,
-       0xbd50e3f0,
-       0xbd34bd24,
-/* 0x0421: init_unk_loop */
-       0x6821f444,
-       0xf400f6b0,
-       0xf7f00f0b,
-       0x04f2bb01,
-       0xb6054ffd,
-/* 0x0436: init_unk_next */
-       0x20b60130,
-       0x04e0b601,
-       0xf40126b0,
-/* 0x0442: init_unk_done */
-       0x0380e21b,
-       0x08048007,
-       0x010027f1,
-       0xcf0223f0,
-       0x34bd0022,
-       0xf1082595,
-       0xf0c00007,
-       0x05d00103,
+       0xf10f24b6,
+       0xf0c90007,
+       0x02d00103,
        0xf104bd00,
-       0xf0c10007,
-       0x05d00103,
-       0x9804bd00,
-       0x0f98000e,
-       0x5021f501,
-       0x002fbb01,
-       0x98003fbb,
-       0x0f98010e,
-       0x5021f502,
-       0x050e9801,
-       0xbb00effd,
-       0x3ebb002e,
-       0x020e9800,
-       0xf5030f98,
-       0x98015021,
-       0xeffd070e,
-       0x002ebb00,
-       0xb6003ebb,
-       0x07f10235,
-       0x03f0d300,
-       0x0003d001,
-       0x25b604bd,
-       0x0635b608,
-       0xb60120b6,
-       0x24b60130,
-       0x0834b608,
-       0xf5022fb9,
-       0xbb02d321,
-       0x07f1003f,
-       0x03f00100,
-       0x0003d002,
-       0x24bd04bd,
-       0xf11f29f0,
-       0xf0080007,
-       0x02d00203,
-/* 0x04f3: main */
-       0xf404bd00,
-       0x28f40031,
-       0x24d7f000,
-       0xf43921f4,
-       0xe4b0f401,
-       0x1e18f404,
-       0xf00181fe,
-       0x20bd0627,
-       0xb60412fd,
-       0x1efd01e4,
-       0x0018fe05,
-       0x05e821f5,
-/* 0x0523: main_not_ctx_xfer */
-       0x94d30ef4,
-       0xf5f010ef,
-       0x7e21f501,
-       0xc60ef403,
-/* 0x0530: ih */
-       0x88fe80f9,
-       0xf980f901,
-       0xf9a0f990,
-       0xf9d0f9b0,
-       0xbdf0f9e0,
-       0x00a7f104,
-       0x00a3f002,
-       0xc400aacf,
-       0x0bf404ab,
-       0x24d7f02c,
-       0x1a00e7f1,
-       0xcf00e3f0,
-       0xf7f100ee,
-       0xf3f01900,
-       0x00ffcf00,
-       0xf00421f4,
-       0x07f101e7,
-       0x03f01d00,
-       0x000ed000,
-/* 0x057e: ih_no_fifo */
+       0xf00c30e7,
+       0x24bd50e3,
+       0x44bd34bd,
+/* 0x0430: init_unk_loop */
+       0xb06821f4,
+       0x0bf400f6,
+       0x01f7f00f,
+       0xfd04f2bb,
+       0x30b6054f,
+/* 0x0445: init_unk_next */
+       0x0120b601,
+       0xb004e0b6,
+       0x1bf40126,
+/* 0x0451: init_unk_done */
+       0x070380e2,
+       0xf1080480,
+       0xf0010027,
+       0x22cf0223,
+       0x9534bd00,
+       0x07f10825,
+       0x03f0c000,
+       0x0005d001,
        0x07f104bd,
-       0x03f00100,
-       0x000ad000,
-       0xf0fc04bd,
-       0xd0fce0fc,
-       0xa0fcb0fc,
-       0x80fc90fc,
-       0xfc0088fe,
-       0x0032f480,
-/* 0x05a2: hub_barrier_done */
-       0xf7f001f8,
-       0x040e9801,
-       0xb904febb,
-       0xe7f102ff,
-       0xe3f09418,
-       0x9d21f440,
-/* 0x05ba: ctx_redswitch */
-       0xf7f000f8,
-       0x0007f120,
-       0x0103f085,
-       0xbd000fd0,
-       0x08e7f004,
-/* 0x05cc: ctx_redswitch_delay */
-       0xf401e2b6,
-       0xf5f1fd1b,
-       0xf5f10800,
-       0x07f10200,
-       0x03f08500,
-       0x000fd001,
-       0x00f804bd,
-/* 0x05e8: ctx_xfer */
-       0x810007f1,
+       0x03f0c100,
+       0x0005d001,
+       0x0e9804bd,
+       0x010f9800,
+       0x015021f5,
+       0xbb002fbb,
+       0x0e98003f,
+       0x020f9801,
+       0x015021f5,
+       0xfd050e98,
+       0x2ebb00ef,
+       0x003ebb00,
+       0x98020e98,
+       0x21f5030f,
+       0x0e980150,
+       0x00effd07,
+       0xbb002ebb,
+       0x35b6003e,
+       0x0007f102,
+       0x0103f0d3,
+       0xbd0003d0,
+       0x0825b604,
+       0xb60635b6,
+       0x30b60120,
+       0x0824b601,
+       0xb90834b6,
+       0x21f5022f,
+       0x2fbb02d3,
+       0x003fbb00,
+       0x010007f1,
        0xd00203f0,
-       0x04bd000f,
-       0xf50711f4,
-/* 0x05fb: ctx_xfer_not_load */
-       0xf505ba21,
-       0xbd026a21,
-       0xfc07f124,
-       0x0203f047,
+       0x04bd0003,
+       0x29f024bd,
+       0x0007f11f,
+       0x0203f008,
        0xbd0002d0,
-       0x012cf004,
-       0xf10320b6,
-       0xf04afc07,
+/* 0x0505: main */
+       0x0031f404,
+       0xf00028f4,
+       0x21f424d7,
+       0xf401f439,
+       0xf404e4b0,
+       0x81fe1e18,
+       0x0627f001,
+       0x12fd20bd,
+       0x01e4b604,
+       0xfe051efd,
+       0x21f50018,
+       0x0ef405fa,
+/* 0x0535: main_not_ctx_xfer */
+       0x10ef94d3,
+       0xf501f5f0,
+       0xf4037e21,
+/* 0x0542: ih */
+       0x80f9c60e,
+       0xf90188fe,
+       0xf990f980,
+       0xf9b0f9a0,
+       0xf9e0f9d0,
+       0xf104bdf0,
+       0xf00200a7,
+       0xaacf00a3,
+       0x04abc400,
+       0xf02c0bf4,
+       0xe7f124d7,
+       0xe3f01a00,
+       0x00eecf00,
+       0x1900f7f1,
+       0xcf00f3f0,
+       0x21f400ff,
+       0x01e7f004,
+       0x1d0007f1,
+       0xd00003f0,
+       0x04bd000e,
+/* 0x0590: ih_no_fifo */
+       0x010007f1,
+       0xd00003f0,
+       0x04bd000a,
+       0xe0fcf0fc,
+       0xb0fcd0fc,
+       0x90fca0fc,
+       0x88fe80fc,
+       0xf480fc00,
+       0x01f80032,
+/* 0x05b4: hub_barrier_done */
+       0x9801f7f0,
+       0xfebb040e,
+       0x02ffb904,
+       0x9418e7f1,
+       0xf440e3f0,
+       0x00f89d21,
+/* 0x05cc: ctx_redswitch */
+       0xf120f7f0,
+       0xf0850007,
+       0x0fd00103,
+       0xf004bd00,
+/* 0x05de: ctx_redswitch_delay */
+       0xe2b608e7,
+       0xfd1bf401,
+       0x0800f5f1,
+       0x0200f5f1,
+       0x850007f1,
+       0xd00103f0,
+       0x04bd000f,
+/* 0x05fa: ctx_xfer */
+       0x07f100f8,
+       0x03f08100,
+       0x000fd002,
+       0x11f404bd,
+       0xcc21f507,
+/* 0x060d: ctx_xfer_not_load */
+       0x6a21f505,
+       0xf124bd02,
+       0xf047fc07,
        0x02d00203,
        0xf004bd00,
-       0xa5f001ac,
-       0x00b7f102,
-       0x50b3f000,
-       0xb6040c98,
-       0xbcbb0fc4,
-       0x000c9800,
-       0xf0010d98,
-       0x21f500e7,
-       0xacf0016f,
-       0x00b7f101,
-       0x50b3f040,
-       0xb6040c98,
-       0xbcbb0fc4,
-       0x010c9800,
-       0x98020d98,
-       0xe7f1060f,
-       0x21f50800,
-       0xacf0016f,
-       0x04a5f001,
-       0x3000b7f1,
-       0x9850b3f0,
-       0xc4b6040c,
-       0x00bcbb0f,
-       0x98020c98,
-       0x0f98030d,
-       0x00e7f108,
-       0x6f21f502,
-       0x5e21f501,
-       0x0601f402,
-/* 0x0697: ctx_xfer_post */
-       0xf50712f4,
-/* 0x069b: ctx_xfer_done */
-       0xf5027f21,
-       0xf805a221,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+       0x20b6012c,
+       0xfc07f103,
+       0x0203f04a,
+       0xbd0002d0,
+       0x01acf004,
+       0xf102a5f0,
+       0xf00000b7,
+       0x0c9850b3,
+       0x0fc4b604,
+       0x9800bcbb,
+       0x0d98000c,
+       0x00e7f001,
+       0x016f21f5,
+       0xf101acf0,
+       0xf04000b7,
+       0x0c9850b3,
+       0x0fc4b604,
+       0x9800bcbb,
+       0x0d98010c,
+       0x060f9802,
+       0x0800e7f1,
+       0x016f21f5,
+       0xf001acf0,
+       0xb7f104a5,
+       0xb3f03000,
+       0x040c9850,
+       0xbb0fc4b6,
+       0x0c9800bc,
+       0x030d9802,
+       0xf1080f98,
+       0xf50200e7,
+       0xf5016f21,
+       0xf4025e21,
+       0x12f40601,
+/* 0x06a9: ctx_xfer_post */
+       0x7f21f507,
+/* 0x06ad: ctx_xfer_done */
+       0xb421f502,
+       0x0000f805,
        0x00000000,
        0x00000000,
        0x00000000,
index 49020fff4317b0294e216a499e456c97c2658137..2f596433c2220048fd55a7ee252f74619f7e041e 100644 (file)
@@ -314,7 +314,7 @@ uint32_t gk104_grgpc_code[] = {
        0x03f01200,
        0x0002d000,
        0x17f104bd,
-       0x10fe0530,
+       0x10fe0542,
        0x0007f100,
        0x0003f007,
        0xbd0000d0,
@@ -333,188 +333,188 @@ uint32_t gk104_grgpc_code[] = {
        0xf0860027,
        0x22cf0123,
        0x04028000,
-       0x0c30e7f1,
-       0xbd50e3f0,
-       0xbd34bd24,
-/* 0x0421: init_unk_loop */
-       0x6821f444,
-       0xf400f6b0,
-       0xf7f00f0b,
-       0x04f2bb01,
-       0xb6054ffd,
-/* 0x0436: init_unk_next */
-       0x20b60130,
-       0x04e0b601,
-       0xf40126b0,
-/* 0x0442: init_unk_done */
-       0x0380e21b,
-       0x08048007,
-       0x010027f1,
-       0xcf0223f0,
-       0x34bd0022,
-       0xf1082595,
-       0xf0c00007,
-       0x05d00103,
+       0xf10f24b6,
+       0xf0c90007,
+       0x02d00103,
        0xf104bd00,
-       0xf0c10007,
-       0x05d00103,
-       0x9804bd00,
-       0x0f98000e,
-       0x5021f501,
-       0x002fbb01,
-       0x98003fbb,
-       0x0f98010e,
-       0x5021f502,
-       0x050e9801,
-       0xbb00effd,
-       0x3ebb002e,
-       0x020e9800,
-       0xf5030f98,
-       0x98015021,
-       0xeffd070e,
-       0x002ebb00,
-       0xb6003ebb,
-       0x07f10235,
-       0x03f0d300,
-       0x0003d001,
-       0x25b604bd,
-       0x0635b608,
-       0xb60120b6,
-       0x24b60130,
-       0x0834b608,
-       0xf5022fb9,
-       0xbb02d321,
-       0x07f1003f,
-       0x03f00100,
-       0x0003d002,
-       0x24bd04bd,
-       0xf11f29f0,
-       0xf0080007,
-       0x02d00203,
-/* 0x04f3: main */
-       0xf404bd00,
-       0x28f40031,
-       0x24d7f000,
-       0xf43921f4,
-       0xe4b0f401,
-       0x1e18f404,
-       0xf00181fe,
-       0x20bd0627,
-       0xb60412fd,
-       0x1efd01e4,
-       0x0018fe05,
-       0x05e821f5,
-/* 0x0523: main_not_ctx_xfer */
-       0x94d30ef4,
-       0xf5f010ef,
-       0x7e21f501,
-       0xc60ef403,
-/* 0x0530: ih */
-       0x88fe80f9,
-       0xf980f901,
-       0xf9a0f990,
-       0xf9d0f9b0,
-       0xbdf0f9e0,
-       0x00a7f104,
-       0x00a3f002,
-       0xc400aacf,
-       0x0bf404ab,
-       0x24d7f02c,
-       0x1a00e7f1,
-       0xcf00e3f0,
-       0xf7f100ee,
-       0xf3f01900,
-       0x00ffcf00,
-       0xf00421f4,
-       0x07f101e7,
-       0x03f01d00,
-       0x000ed000,
-/* 0x057e: ih_no_fifo */
+       0xf00c30e7,
+       0x24bd50e3,
+       0x44bd34bd,
+/* 0x0430: init_unk_loop */
+       0xb06821f4,
+       0x0bf400f6,
+       0x01f7f00f,
+       0xfd04f2bb,
+       0x30b6054f,
+/* 0x0445: init_unk_next */
+       0x0120b601,
+       0xb004e0b6,
+       0x1bf40126,
+/* 0x0451: init_unk_done */
+       0x070380e2,
+       0xf1080480,
+       0xf0010027,
+       0x22cf0223,
+       0x9534bd00,
+       0x07f10825,
+       0x03f0c000,
+       0x0005d001,
        0x07f104bd,
-       0x03f00100,
-       0x000ad000,
-       0xf0fc04bd,
-       0xd0fce0fc,
-       0xa0fcb0fc,
-       0x80fc90fc,
-       0xfc0088fe,
-       0x0032f480,
-/* 0x05a2: hub_barrier_done */
-       0xf7f001f8,
-       0x040e9801,
-       0xb904febb,
-       0xe7f102ff,
-       0xe3f09418,
-       0x9d21f440,
-/* 0x05ba: ctx_redswitch */
-       0xf7f000f8,
-       0x0007f120,
-       0x0103f085,
-       0xbd000fd0,
-       0x08e7f004,
-/* 0x05cc: ctx_redswitch_delay */
-       0xf401e2b6,
-       0xf5f1fd1b,
-       0xf5f10800,
-       0x07f10200,
-       0x03f08500,
-       0x000fd001,
-       0x00f804bd,
-/* 0x05e8: ctx_xfer */
-       0x810007f1,
+       0x03f0c100,
+       0x0005d001,
+       0x0e9804bd,
+       0x010f9800,
+       0x015021f5,
+       0xbb002fbb,
+       0x0e98003f,
+       0x020f9801,
+       0x015021f5,
+       0xfd050e98,
+       0x2ebb00ef,
+       0x003ebb00,
+       0x98020e98,
+       0x21f5030f,
+       0x0e980150,
+       0x00effd07,
+       0xbb002ebb,
+       0x35b6003e,
+       0x0007f102,
+       0x0103f0d3,
+       0xbd0003d0,
+       0x0825b604,
+       0xb60635b6,
+       0x30b60120,
+       0x0824b601,
+       0xb90834b6,
+       0x21f5022f,
+       0x2fbb02d3,
+       0x003fbb00,
+       0x010007f1,
        0xd00203f0,
-       0x04bd000f,
-       0xf50711f4,
-/* 0x05fb: ctx_xfer_not_load */
-       0xf505ba21,
-       0xbd026a21,
-       0xfc07f124,
-       0x0203f047,
+       0x04bd0003,
+       0x29f024bd,
+       0x0007f11f,
+       0x0203f008,
        0xbd0002d0,
-       0x012cf004,
-       0xf10320b6,
-       0xf04afc07,
+/* 0x0505: main */
+       0x0031f404,
+       0xf00028f4,
+       0x21f424d7,
+       0xf401f439,
+       0xf404e4b0,
+       0x81fe1e18,
+       0x0627f001,
+       0x12fd20bd,
+       0x01e4b604,
+       0xfe051efd,
+       0x21f50018,
+       0x0ef405fa,
+/* 0x0535: main_not_ctx_xfer */
+       0x10ef94d3,
+       0xf501f5f0,
+       0xf4037e21,
+/* 0x0542: ih */
+       0x80f9c60e,
+       0xf90188fe,
+       0xf990f980,
+       0xf9b0f9a0,
+       0xf9e0f9d0,
+       0xf104bdf0,
+       0xf00200a7,
+       0xaacf00a3,
+       0x04abc400,
+       0xf02c0bf4,
+       0xe7f124d7,
+       0xe3f01a00,
+       0x00eecf00,
+       0x1900f7f1,
+       0xcf00f3f0,
+       0x21f400ff,
+       0x01e7f004,
+       0x1d0007f1,
+       0xd00003f0,
+       0x04bd000e,
+/* 0x0590: ih_no_fifo */
+       0x010007f1,
+       0xd00003f0,
+       0x04bd000a,
+       0xe0fcf0fc,
+       0xb0fcd0fc,
+       0x90fca0fc,
+       0x88fe80fc,
+       0xf480fc00,
+       0x01f80032,
+/* 0x05b4: hub_barrier_done */
+       0x9801f7f0,
+       0xfebb040e,
+       0x02ffb904,
+       0x9418e7f1,
+       0xf440e3f0,
+       0x00f89d21,
+/* 0x05cc: ctx_redswitch */
+       0xf120f7f0,
+       0xf0850007,
+       0x0fd00103,
+       0xf004bd00,
+/* 0x05de: ctx_redswitch_delay */
+       0xe2b608e7,
+       0xfd1bf401,
+       0x0800f5f1,
+       0x0200f5f1,
+       0x850007f1,
+       0xd00103f0,
+       0x04bd000f,
+/* 0x05fa: ctx_xfer */
+       0x07f100f8,
+       0x03f08100,
+       0x000fd002,
+       0x11f404bd,
+       0xcc21f507,
+/* 0x060d: ctx_xfer_not_load */
+       0x6a21f505,
+       0xf124bd02,
+       0xf047fc07,
        0x02d00203,
        0xf004bd00,
-       0xa5f001ac,
-       0x00b7f102,
-       0x50b3f000,
-       0xb6040c98,
-       0xbcbb0fc4,
-       0x000c9800,
-       0xf0010d98,
-       0x21f500e7,
-       0xacf0016f,
-       0x00b7f101,
-       0x50b3f040,
-       0xb6040c98,
-       0xbcbb0fc4,
-       0x010c9800,
-       0x98020d98,
-       0xe7f1060f,
-       0x21f50800,
-       0xacf0016f,
-       0x04a5f001,
-       0x3000b7f1,
-       0x9850b3f0,
-       0xc4b6040c,
-       0x00bcbb0f,
-       0x98020c98,
-       0x0f98030d,
-       0x00e7f108,
-       0x6f21f502,
-       0x5e21f501,
-       0x0601f402,
-/* 0x0697: ctx_xfer_post */
-       0xf50712f4,
-/* 0x069b: ctx_xfer_done */
-       0xf5027f21,
-       0xf805a221,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+       0x20b6012c,
+       0xfc07f103,
+       0x0203f04a,
+       0xbd0002d0,
+       0x01acf004,
+       0xf102a5f0,
+       0xf00000b7,
+       0x0c9850b3,
+       0x0fc4b604,
+       0x9800bcbb,
+       0x0d98000c,
+       0x00e7f001,
+       0x016f21f5,
+       0xf101acf0,
+       0xf04000b7,
+       0x0c9850b3,
+       0x0fc4b604,
+       0x9800bcbb,
+       0x0d98010c,
+       0x060f9802,
+       0x0800e7f1,
+       0x016f21f5,
+       0xf001acf0,
+       0xb7f104a5,
+       0xb3f03000,
+       0x040c9850,
+       0xbb0fc4b6,
+       0x0c9800bc,
+       0x030d9802,
+       0xf1080f98,
+       0xf50200e7,
+       0xf5016f21,
+       0xf4025e21,
+       0x12f40601,
+/* 0x06a9: ctx_xfer_post */
+       0x7f21f507,
+/* 0x06ad: ctx_xfer_done */
+       0xb421f502,
+       0x0000f805,
        0x00000000,
        0x00000000,
        0x00000000,
index c95b07e3bce5d192ed14061f5a1a2cdf416f3e53..ee8e54db8fc9ed83bd5da4c176de4e4fbe6bed73 100644 (file)
@@ -314,7 +314,7 @@ uint32_t gk110_grgpc_code[] = {
        0x03f01200,
        0x0002d000,
        0x17f104bd,
-       0x10fe0530,
+       0x10fe0542,
        0x0007f100,
        0x0003f007,
        0xbd0000d0,
@@ -333,188 +333,188 @@ uint32_t gk110_grgpc_code[] = {
        0xf0860027,
        0x22cf0123,
        0x04028000,
-       0x0c30e7f1,
-       0xbd50e3f0,
-       0xbd34bd24,
-/* 0x0421: init_unk_loop */
-       0x6821f444,
-       0xf400f6b0,
-       0xf7f00f0b,
-       0x04f2bb01,
-       0xb6054ffd,
-/* 0x0436: init_unk_next */
-       0x20b60130,
-       0x04e0b601,
-       0xf40226b0,
-/* 0x0442: init_unk_done */
-       0x0380e21b,
-       0x08048007,
-       0x010027f1,
-       0xcf0223f0,
-       0x34bd0022,
-       0xf1082595,
-       0xf0c00007,
-       0x05d00103,
+       0xf10f24b6,
+       0xf0c90007,
+       0x02d00103,
        0xf104bd00,
-       0xf0c10007,
-       0x05d00103,
-       0x9804bd00,
-       0x0f98000e,
-       0x5021f501,
-       0x002fbb01,
-       0x98003fbb,
-       0x0f98010e,
-       0x5021f502,
-       0x050e9801,
-       0xbb00effd,
-       0x3ebb002e,
-       0x020e9800,
-       0xf5030f98,
-       0x98015021,
-       0xeffd070e,
-       0x002ebb00,
-       0xb6003ebb,
-       0x07f10235,
-       0x03f0d300,
-       0x0003d001,
-       0x25b604bd,
-       0x0635b608,
-       0xb60120b6,
-       0x24b60130,
-       0x0834b608,
-       0xf5022fb9,
-       0xbb02d321,
-       0x07f1003f,
-       0x03f00100,
-       0x0003d002,
-       0x24bd04bd,
-       0xf11f29f0,
-       0xf0300007,
-       0x02d00203,
-/* 0x04f3: main */
-       0xf404bd00,
-       0x28f40031,
-       0x24d7f000,
-       0xf43921f4,
-       0xe4b0f401,
-       0x1e18f404,
-       0xf00181fe,
-       0x20bd0627,
-       0xb60412fd,
-       0x1efd01e4,
-       0x0018fe05,
-       0x05e821f5,
-/* 0x0523: main_not_ctx_xfer */
-       0x94d30ef4,
-       0xf5f010ef,
-       0x7e21f501,
-       0xc60ef403,
-/* 0x0530: ih */
-       0x88fe80f9,
-       0xf980f901,
-       0xf9a0f990,
-       0xf9d0f9b0,
-       0xbdf0f9e0,
-       0x00a7f104,
-       0x00a3f002,
-       0xc400aacf,
-       0x0bf404ab,
-       0x24d7f02c,
-       0x1a00e7f1,
-       0xcf00e3f0,
-       0xf7f100ee,
-       0xf3f01900,
-       0x00ffcf00,
-       0xf00421f4,
-       0x07f101e7,
-       0x03f01d00,
-       0x000ed000,
-/* 0x057e: ih_no_fifo */
+       0xf00c30e7,
+       0x24bd50e3,
+       0x44bd34bd,
+/* 0x0430: init_unk_loop */
+       0xb06821f4,
+       0x0bf400f6,
+       0x01f7f00f,
+       0xfd04f2bb,
+       0x30b6054f,
+/* 0x0445: init_unk_next */
+       0x0120b601,
+       0xb004e0b6,
+       0x1bf40226,
+/* 0x0451: init_unk_done */
+       0x070380e2,
+       0xf1080480,
+       0xf0010027,
+       0x22cf0223,
+       0x9534bd00,
+       0x07f10825,
+       0x03f0c000,
+       0x0005d001,
        0x07f104bd,
-       0x03f00100,
-       0x000ad000,
-       0xf0fc04bd,
-       0xd0fce0fc,
-       0xa0fcb0fc,
-       0x80fc90fc,
-       0xfc0088fe,
-       0x0032f480,
-/* 0x05a2: hub_barrier_done */
-       0xf7f001f8,
-       0x040e9801,
-       0xb904febb,
-       0xe7f102ff,
-       0xe3f09418,
-       0x9d21f440,
-/* 0x05ba: ctx_redswitch */
-       0xf7f000f8,
-       0x0007f120,
-       0x0103f085,
-       0xbd000fd0,
-       0x08e7f004,
-/* 0x05cc: ctx_redswitch_delay */
-       0xf401e2b6,
-       0xf5f1fd1b,
-       0xf5f10800,
-       0x07f10200,
-       0x03f08500,
-       0x000fd001,
-       0x00f804bd,
-/* 0x05e8: ctx_xfer */
-       0x810007f1,
+       0x03f0c100,
+       0x0005d001,
+       0x0e9804bd,
+       0x010f9800,
+       0x015021f5,
+       0xbb002fbb,
+       0x0e98003f,
+       0x020f9801,
+       0x015021f5,
+       0xfd050e98,
+       0x2ebb00ef,
+       0x003ebb00,
+       0x98020e98,
+       0x21f5030f,
+       0x0e980150,
+       0x00effd07,
+       0xbb002ebb,
+       0x35b6003e,
+       0x0007f102,
+       0x0103f0d3,
+       0xbd0003d0,
+       0x0825b604,
+       0xb60635b6,
+       0x30b60120,
+       0x0824b601,
+       0xb90834b6,
+       0x21f5022f,
+       0x2fbb02d3,
+       0x003fbb00,
+       0x010007f1,
        0xd00203f0,
-       0x04bd000f,
-       0xf50711f4,
-/* 0x05fb: ctx_xfer_not_load */
-       0xf505ba21,
-       0xbd026a21,
-       0xfc07f124,
-       0x0203f047,
+       0x04bd0003,
+       0x29f024bd,
+       0x0007f11f,
+       0x0203f030,
        0xbd0002d0,
-       0x012cf004,
-       0xf10320b6,
-       0xf04afc07,
+/* 0x0505: main */
+       0x0031f404,
+       0xf00028f4,
+       0x21f424d7,
+       0xf401f439,
+       0xf404e4b0,
+       0x81fe1e18,
+       0x0627f001,
+       0x12fd20bd,
+       0x01e4b604,
+       0xfe051efd,
+       0x21f50018,
+       0x0ef405fa,
+/* 0x0535: main_not_ctx_xfer */
+       0x10ef94d3,
+       0xf501f5f0,
+       0xf4037e21,
+/* 0x0542: ih */
+       0x80f9c60e,
+       0xf90188fe,
+       0xf990f980,
+       0xf9b0f9a0,
+       0xf9e0f9d0,
+       0xf104bdf0,
+       0xf00200a7,
+       0xaacf00a3,
+       0x04abc400,
+       0xf02c0bf4,
+       0xe7f124d7,
+       0xe3f01a00,
+       0x00eecf00,
+       0x1900f7f1,
+       0xcf00f3f0,
+       0x21f400ff,
+       0x01e7f004,
+       0x1d0007f1,
+       0xd00003f0,
+       0x04bd000e,
+/* 0x0590: ih_no_fifo */
+       0x010007f1,
+       0xd00003f0,
+       0x04bd000a,
+       0xe0fcf0fc,
+       0xb0fcd0fc,
+       0x90fca0fc,
+       0x88fe80fc,
+       0xf480fc00,
+       0x01f80032,
+/* 0x05b4: hub_barrier_done */
+       0x9801f7f0,
+       0xfebb040e,
+       0x02ffb904,
+       0x9418e7f1,
+       0xf440e3f0,
+       0x00f89d21,
+/* 0x05cc: ctx_redswitch */
+       0xf120f7f0,
+       0xf0850007,
+       0x0fd00103,
+       0xf004bd00,
+/* 0x05de: ctx_redswitch_delay */
+       0xe2b608e7,
+       0xfd1bf401,
+       0x0800f5f1,
+       0x0200f5f1,
+       0x850007f1,
+       0xd00103f0,
+       0x04bd000f,
+/* 0x05fa: ctx_xfer */
+       0x07f100f8,
+       0x03f08100,
+       0x000fd002,
+       0x11f404bd,
+       0xcc21f507,
+/* 0x060d: ctx_xfer_not_load */
+       0x6a21f505,
+       0xf124bd02,
+       0xf047fc07,
        0x02d00203,
        0xf004bd00,
-       0xa5f001ac,
-       0x00b7f102,
-       0x50b3f000,
-       0xb6040c98,
-       0xbcbb0fc4,
-       0x000c9800,
-       0xf0010d98,
-       0x21f500e7,
-       0xacf0016f,
-       0x00b7f101,
-       0x50b3f040,
-       0xb6040c98,
-       0xbcbb0fc4,
-       0x010c9800,
-       0x98020d98,
-       0xe7f1060f,
-       0x21f50800,
-       0xacf0016f,
-       0x04a5f001,
-       0x3000b7f1,
-       0x9850b3f0,
-       0xc4b6040c,
-       0x00bcbb0f,
-       0x98020c98,
-       0x0f98030d,
-       0x00e7f108,
-       0x6f21f502,
-       0x5e21f501,
-       0x0601f402,
-/* 0x0697: ctx_xfer_post */
-       0xf50712f4,
-/* 0x069b: ctx_xfer_done */
-       0xf5027f21,
-       0xf805a221,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+       0x20b6012c,
+       0xfc07f103,
+       0x0203f04a,
+       0xbd0002d0,
+       0x01acf004,
+       0xf102a5f0,
+       0xf00000b7,
+       0x0c9850b3,
+       0x0fc4b604,
+       0x9800bcbb,
+       0x0d98000c,
+       0x00e7f001,
+       0x016f21f5,
+       0xf101acf0,
+       0xf04000b7,
+       0x0c9850b3,
+       0x0fc4b604,
+       0x9800bcbb,
+       0x0d98010c,
+       0x060f9802,
+       0x0800e7f1,
+       0x016f21f5,
+       0xf001acf0,
+       0xb7f104a5,
+       0xb3f03000,
+       0x040c9850,
+       0xbb0fc4b6,
+       0x0c9800bc,
+       0x030d9802,
+       0xf1080f98,
+       0xf50200e7,
+       0xf5016f21,
+       0xf4025e21,
+       0x12f40601,
+/* 0x06a9: ctx_xfer_post */
+       0x7f21f507,
+/* 0x06ad: ctx_xfer_done */
+       0xb421f502,
+       0x0000f805,
        0x00000000,
        0x00000000,
        0x00000000,
index 7e1c28ee7591db60aa11f9673cb1cb08b4e5c0de..fbcc342f896f144708e059093156c0e99210e952 100644 (file)
@@ -276,7 +276,7 @@ uint32_t gk208_grgpc_code[] = {
        0x02020014,
        0xf6120040,
        0x04bd0002,
-       0xfe047241,
+       0xfe048141,
        0x00400010,
        0x0000f607,
        0x040204bd,
@@ -291,20 +291,23 @@ uint32_t gk208_grgpc_code[] = {
        0x820603b5,
        0xcf018600,
        0x02b50022,
+       0x0f24b604,
+       0x01c90080,
+       0xbd0002f6,
        0x0c308e04,
        0xbd24bd50,
-/* 0x0377: init_unk_loop */
+/* 0x0383: init_unk_loop */
        0x7e44bd34,
        0xb0000065,
        0x0bf400f6,
        0xbb010f0e,
        0x4ffd04f2,
        0x0130b605,
-/* 0x038c: init_unk_next */
+/* 0x0398: init_unk_next */
        0xb60120b6,
        0x26b004e0,
        0xe21bf401,
-/* 0x0398: init_unk_done */
+/* 0x03a4: init_unk_done */
        0xb50703b5,
        0x00820804,
        0x22cf0201,
@@ -338,121 +341,118 @@ uint32_t gk208_grgpc_code[] = {
        0xb60824b6,
        0x2fb20834,
        0x0002687e,
-       0x80003fbb,
-       0xf6020100,
-       0x04bd0003,
-       0x29f024bd,
-       0x3000801f,
-       0x0002f602,
-/* 0x0436: main */
-       0x31f404bd,
-       0x0028f400,
-       0x377e240d,
-       0x01f40000,
-       0x04e4b0f4,
-       0xfe1d18f4,
-       0x06020181,
-       0x12fd20bd,
-       0x01e4b604,
-       0xfe051efd,
-       0x097e0018,
-       0x0ef40005,
-/* 0x0465: main_not_ctx_xfer */
-       0x10ef94d4,
-       0x7e01f5f0,
-       0xf40002f8,
-/* 0x0472: ih */
-       0x80f9c70e,
-       0xf90188fe,
-       0xf990f980,
-       0xf9b0f9a0,
-       0xf9e0f9d0,
-       0x4a04bdf0,
-       0xaacf0200,
-       0x04abc400,
-       0x0d1f0bf4,
-       0x1a004e24,
-       0x4f00eecf,
-       0xffcf1900,
-       0x00047e00,
-       0x40010e00,
-       0x0ef61d00,
-/* 0x04af: ih_no_fifo */
-       0x4004bd00,
-       0x0af60100,
-       0xfc04bd00,
-       0xfce0fcf0,
-       0xfcb0fcd0,
-       0xfc90fca0,
-       0x0088fe80,
-       0x32f480fc,
-/* 0x04cf: hub_barrier_done */
-       0x0f01f800,
-       0x040e9801,
-       0xb204febb,
-       0x94188eff,
-       0x008f7e40,
-/* 0x04e3: ctx_redswitch */
-       0x0f00f800,
-       0x85008020,
+       0xbb002fbb,
+       0x0080003f,
+       0x03f60201,
+       0xbd04bd00,
+       0x1f29f024,
+       0x02300080,
+       0xbd0002f6,
+/* 0x0445: main */
+       0x0031f404,
+       0x0d0028f4,
+       0x00377e24,
+       0xf401f400,
+       0xf404e4b0,
+       0x81fe1d18,
+       0xbd060201,
+       0x0412fd20,
+       0xfd01e4b6,
+       0x18fe051e,
+       0x05187e00,
+       0xd40ef400,
+/* 0x0474: main_not_ctx_xfer */
+       0xf010ef94,
+       0xf87e01f5,
+       0x0ef40002,
+/* 0x0481: ih */
+       0xfe80f9c7,
+       0x80f90188,
+       0xa0f990f9,
+       0xd0f9b0f9,
+       0xf0f9e0f9,
+       0x004a04bd,
+       0x00aacf02,
+       0xf404abc4,
+       0x240d1f0b,
+       0xcf1a004e,
+       0x004f00ee,
+       0x00ffcf19,
+       0x0000047e,
+       0x0040010e,
+       0x000ef61d,
+/* 0x04be: ih_no_fifo */
+       0x004004bd,
+       0x000af601,
+       0xf0fc04bd,
+       0xd0fce0fc,
+       0xa0fcb0fc,
+       0x80fc90fc,
+       0xfc0088fe,
+       0x0032f480,
+/* 0x04de: hub_barrier_done */
+       0x010f01f8,
+       0xbb040e98,
+       0xffb204fe,
+       0x4094188e,
+       0x00008f7e,
+/* 0x04f2: ctx_redswitch */
+       0x200f00f8,
+       0x01850080,
+       0xbd000ff6,
+/* 0x04ff: ctx_redswitch_delay */
+       0xb6080e04,
+       0x1bf401e2,
+       0x00f5f1fd,
+       0x00f5f108,
+       0x85008002,
        0x000ff601,
-       0x080e04bd,
-/* 0x04f0: ctx_redswitch_delay */
-       0xf401e2b6,
-       0xf5f1fd1b,
-       0xf5f10800,
-       0x00800200,
-       0x0ff60185,
-       0xf804bd00,
-/* 0x0509: ctx_xfer */
-       0x81008000,
-       0x000ff602,
-       0x11f404bd,
-       0x04e37e07,
-/* 0x0519: ctx_xfer_not_load */
-       0x02167e00,
-       0x8024bd00,
-       0xf60247fc,
-       0x04bd0002,
-       0xb6012cf0,
-       0xfc800320,
-       0x02f6024a,
+       0x00f804bd,
+/* 0x0518: ctx_xfer */
+       0x02810080,
+       0xbd000ff6,
+       0x0711f404,
+       0x0004f27e,
+/* 0x0528: ctx_xfer_not_load */
+       0x0002167e,
+       0xfc8024bd,
+       0x02f60247,
        0xf004bd00,
-       0xa5f001ac,
-       0x00008b02,
-       0x040c9850,
-       0xbb0fc4b6,
-       0x0c9800bc,
-       0x010d9800,
-       0x3d7e000e,
-       0xacf00001,
-       0x40008b01,
-       0x040c9850,
-       0xbb0fc4b6,
-       0x0c9800bc,
-       0x020d9801,
-       0x4e060f98,
-       0x3d7e0800,
-       0xacf00001,
-       0x04a5f001,
-       0x5030008b,
+       0x20b6012c,
+       0x4afc8003,
+       0x0002f602,
+       0xacf004bd,
+       0x02a5f001,
+       0x5000008b,
        0xb6040c98,
        0xbcbb0fc4,
-       0x020c9800,
-       0x98030d98,
-       0x004e080f,
-       0x013d7e02,
-       0x020a7e00,
-       0x0601f400,
-/* 0x05a3: ctx_xfer_post */
-       0x7e0712f4,
-/* 0x05a7: ctx_xfer_done */
-       0x7e000227,
-       0xf80004cf,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+       0x000c9800,
+       0x0e010d98,
+       0x013d7e00,
+       0x01acf000,
+       0x5040008b,
+       0xb6040c98,
+       0xbcbb0fc4,
+       0x010c9800,
+       0x98020d98,
+       0x004e060f,
+       0x013d7e08,
+       0x01acf000,
+       0x8b04a5f0,
+       0x98503000,
+       0xc4b6040c,
+       0x00bcbb0f,
+       0x98020c98,
+       0x0f98030d,
+       0x02004e08,
+       0x00013d7e,
+       0x00020a7e,
+       0xf40601f4,
+/* 0x05b2: ctx_xfer_post */
+       0x277e0712,
+/* 0x05b6: ctx_xfer_done */
+       0xde7e0002,
+       0x00f80004,
        0x00000000,
        0x00000000,
        0x00000000,
index e730603891d776d8d27fdb17fa852fcdc91c41a9..47802c7ecca1e78cabd4ce1381fedb0c2ffc6aa3 100644 (file)
@@ -24,7 +24,7 @@
 
 #define NV_PGRAPH_GPCX_UNK__SIZE                                     0x00000002
 
-#define CHIPSET GK208
+#define CHIPSET GM107
 #include "macros.fuc"
 
 .section #gm107_grgpc_data
index 6d53b67dd3c41ab4d0028d841cdd49452607cb5a..51f5c3c6e96607914f5f7ffcc0973f7f4e347bcc 100644 (file)
@@ -41,7 +41,7 @@ uint32_t gm107_grgpc_data[] = {
 };
 
 uint32_t gm107_grgpc_code[] = {
-       0x03140ef5,
+       0x03410ef5,
 /* 0x0004: queue_put */
        0x9800d898,
        0x86f001d9,
@@ -268,187 +268,319 @@ uint32_t gm107_grgpc_code[] = {
        0x409c1c8e,
        0x00008f7e,
        0x00f8e0fc,
-/* 0x0314: init */
-       0x004104bd,
-       0x0011cf42,
-       0x010911e7,
-       0xfe0814b6,
-       0x02020014,
-       0xf6120040,
-       0x04bd0002,
-       0xfe047241,
-       0x00400010,
-       0x0000f607,
-       0x040204bd,
-       0xf6040040,
-       0x04bd0002,
-       0x821031f4,
-       0xcf018200,
-       0x01030022,
-       0xbb1f24f0,
-       0x32b60432,
-       0x0502b501,
-       0x820603b5,
-       0xcf018600,
-       0x02b50022,
-       0x0c308e04,
-       0xbd24bd50,
-/* 0x0377: init_unk_loop */
-       0x7e44bd34,
-       0xb0000065,
-       0x0bf400f6,
-       0xbb010f0e,
-       0x4ffd04f2,
-       0x0130b605,
-/* 0x038c: init_unk_next */
-       0xb60120b6,
-       0x26b004e0,
-       0xe21bf402,
-/* 0x0398: init_unk_done */
-       0xb50703b5,
-       0x00820804,
-       0x22cf0201,
-       0x9534bd00,
-       0x00800825,
-       0x05f601c0,
-       0x8004bd00,
-       0xf601c100,
+/* 0x0314: tpc_strand_wait */
+       0x94bd90f9,
+       0x800a99f0,
+       0xf6023700,
+       0x04bd0009,
+/* 0x0324: tpc_strand_busy */
+       0x033f0089,
+       0xb30099cf,
+       0xbdf90094,
+       0x0a99f094,
+       0x02170080,
+       0xbd0009f6,
+       0xf890fc04,
+/* 0x0341: init */
+       0x4104bd00,
+       0x11cf4200,
+       0x0911e700,
+       0x0814b601,
+       0x020014fe,
+       0x12004002,
+       0xbd0002f6,
+       0x05b04104,
+       0x400010fe,
+       0x00f60700,
+       0x0204bd00,
+       0x04004004,
+       0xbd0002f6,
+       0x1031f404,
+       0x01820082,
+       0x030022cf,
+       0x1f24f001,
+       0xb60432bb,
+       0x02b50132,
+       0x0603b505,
+       0x01860082,
+       0xb50022cf,
+       0x24b60402,
+       0xc900800f,
+       0x0002f601,
+       0x308e04bd,
+       0x24bd500c,
+       0x44bd34bd,
+/* 0x03b0: init_unk_loop */
+       0x0000657e,
+       0xf400f6b0,
+       0x010f0e0b,
+       0xfd04f2bb,
+       0x30b6054f,
+/* 0x03c5: init_unk_next */
+       0x0120b601,
+       0xb004e0b6,
+       0x1bf40226,
+/* 0x03d1: init_unk_done */
+       0x0703b5e2,
+       0x820804b5,
+       0xcf020100,
+       0x34bd0022,
+       0x80082595,
+       0xf601c000,
        0x04bd0005,
-       0x98000e98,
-       0x207e010f,
-       0x2fbb0001,
+       0x01c10080,
+       0xbd0005f6,
+       0x000e9804,
+       0x7e010f98,
+       0xbb000120,
+       0x3fbb002f,
+       0x010e9800,
+       0x7e020f98,
+       0x98000120,
+       0xeffd050e,
+       0x002ebb00,
+       0x98003ebb,
+       0x0f98020e,
+       0x01207e03,
+       0x070e9800,
+       0xbb00effd,
+       0x3ebb002e,
+       0x0235b600,
+       0x01d30080,
+       0xbd0003f6,
+       0x0825b604,
+       0xb60635b6,
+       0x30b60120,
+       0x0824b601,
+       0xb20834b6,
+       0x02687e2f,
+       0x002fbb00,
+       0x0f003fbb,
+       0x8effb23f,
+       0xf0501d60,
+       0x8f7e01e5,
+       0x0c0f0000,
+       0xa88effb2,
+       0xe5f0501d,
+       0x008f7e01,
+       0x03147e00,
+       0xb23f0f00,
+       0x1d608eff,
+       0x01e5f050,
+       0x00008f7e,
+       0xffb2000f,
+       0x501d9c8e,
+       0x7e01e5f0,
+       0x0f00008f,
+       0x03147e01,
+       0x8effb200,
+       0xf0501da8,
+       0x8f7e01e5,
+       0xff0f0000,
+       0x988effb2,
+       0xe5f0501d,
+       0x008f7e01,
+       0xb2020f00,
+       0x1da88eff,
+       0x01e5f050,
+       0x00008f7e,
+       0x0003147e,
+       0x85050498,
+       0x98504000,
+       0x64b60406,
+       0x0056bb0f,
+/* 0x04e0: tpc_strand_init_tpc_loop */
+       0x05705eb8,
+       0x00657e00,
+       0xbdf6b200,
+/* 0x04ed: tpc_strand_init_idx_loop */
+       0x605eb874,
+       0x7fb20005,
+       0x00008f7e,
+       0x05885eb8,
+       0x082f9500,
+       0x00008f7e,
+       0x058c5eb8,
+       0x082f9500,
+       0x00008f7e,
+       0x05905eb8,
+       0x00657e00,
+       0x06f5b600,
+       0xb601f0b6,
+       0x2fbb08f4,
        0x003fbb00,
-       0x98010e98,
-       0x207e020f,
-       0x0e980001,
-       0x00effd05,
-       0xbb002ebb,
-       0x0e98003e,
-       0x030f9802,
-       0x0001207e,
-       0xfd070e98,
-       0x2ebb00ef,
-       0x003ebb00,
-       0x800235b6,
-       0xf601d300,
-       0x04bd0003,
-       0xb60825b6,
-       0x20b60635,
-       0x0130b601,
-       0xb60824b6,
-       0x2fb20834,
-       0x0002687e,
-       0x80003fbb,
-       0xf6020100,
-       0x04bd0003,
-       0x29f024bd,
-       0x3000801f,
-       0x0002f602,
-/* 0x0436: main */
-       0x31f404bd,
-       0x0028f400,
-       0x377e240d,
-       0x01f40000,
-       0x04e4b0f4,
-       0xfe1d18f4,
-       0x06020181,
-       0x12fd20bd,
-       0x01e4b604,
-       0xfe051efd,
-       0x097e0018,
-       0x0ef40005,
-/* 0x0465: main_not_ctx_xfer */
-       0x10ef94d4,
-       0x7e01f5f0,
-       0xf40002f8,
-/* 0x0472: ih */
-       0x80f9c70e,
-       0xf90188fe,
-       0xf990f980,
-       0xf9b0f9a0,
-       0xf9e0f9d0,
-       0x4a04bdf0,
-       0xaacf0200,
-       0x04abc400,
-       0x0d1f0bf4,
-       0x1a004e24,
-       0x4f00eecf,
-       0xffcf1900,
-       0x00047e00,
-       0x40010e00,
-       0x0ef61d00,
-/* 0x04af: ih_no_fifo */
-       0x4004bd00,
-       0x0af60100,
-       0xfc04bd00,
-       0xfce0fcf0,
-       0xfcb0fcd0,
-       0xfc90fca0,
-       0x0088fe80,
-       0x32f480fc,
-/* 0x04cf: hub_barrier_done */
-       0x0f01f800,
-       0x040e9801,
-       0xb204febb,
-       0x94188eff,
-       0x008f7e40,
-/* 0x04e3: ctx_redswitch */
-       0x0f00f800,
-       0x85008020,
-       0x000ff601,
-       0x080e04bd,
-/* 0x04f0: ctx_redswitch_delay */
-       0xf401e2b6,
-       0xf5f1fd1b,
-       0xf5f10800,
-       0x00800200,
-       0x0ff60185,
-       0xf804bd00,
-/* 0x0509: ctx_xfer */
-       0x81008000,
-       0x000ff602,
-       0x11f404bd,
-       0x04e37e07,
-/* 0x0519: ctx_xfer_not_load */
-       0x02167e00,
-       0x8024bd00,
-       0xf60247fc,
+       0xb60170b6,
+       0x1bf40162,
+       0x0050b7bf,
+       0x0142b608,
+       0x0fa81bf4,
+       0x8effb23f,
+       0xf0501d60,
+       0x8f7e01e5,
+       0x0d0f0000,
+       0xa88effb2,
+       0xe5f0501d,
+       0x008f7e01,
+       0x03147e00,
+       0x01008000,
+       0x0003f602,
+       0x24bd04bd,
+       0x801f29f0,
+       0xf6023000,
        0x04bd0002,
-       0xb6012cf0,
-       0xfc800320,
-       0x02f6024a,
+/* 0x0574: main */
+       0xf40031f4,
+       0x240d0028,
+       0x0000377e,
+       0xb0f401f4,
+       0x18f404e4,
+       0x0181fe1d,
+       0x20bd0602,
+       0xb60412fd,
+       0x1efd01e4,
+       0x0018fe05,
+       0x0006477e,
+/* 0x05a3: main_not_ctx_xfer */
+       0x94d40ef4,
+       0xf5f010ef,
+       0x02f87e01,
+       0xc70ef400,
+/* 0x05b0: ih */
+       0x88fe80f9,
+       0xf980f901,
+       0xf9a0f990,
+       0xf9d0f9b0,
+       0xbdf0f9e0,
+       0x02004a04,
+       0xc400aacf,
+       0x0bf404ab,
+       0x4e240d1f,
+       0xeecf1a00,
+       0x19004f00,
+       0x7e00ffcf,
+       0x0e000004,
+       0x1d004001,
+       0xbd000ef6,
+/* 0x05ed: ih_no_fifo */
+       0x01004004,
+       0xbd000af6,
+       0xfcf0fc04,
+       0xfcd0fce0,
+       0xfca0fcb0,
+       0xfe80fc90,
+       0x80fc0088,
+       0xf80032f4,
+/* 0x060d: hub_barrier_done */
+       0x98010f01,
+       0xfebb040e,
+       0x8effb204,
+       0x7e409418,
+       0xf800008f,
+/* 0x0621: ctx_redswitch */
+       0x80200f00,
+       0xf6018500,
+       0x04bd000f,
+/* 0x062e: ctx_redswitch_delay */
+       0xe2b6080e,
+       0xfd1bf401,
+       0x0800f5f1,
+       0x0200f5f1,
+       0x01850080,
+       0xbd000ff6,
+/* 0x0647: ctx_xfer */
+       0x8000f804,
+       0xf6028100,
+       0x04bd000f,
+       0xc48effb2,
+       0xe5f0501d,
+       0x008f7e01,
+       0x0711f400,
+       0x0006217e,
+/* 0x0664: ctx_xfer_not_load */
+       0x0002167e,
+       0xfc8024bd,
+       0x02f60247,
        0xf004bd00,
+       0x20b6012c,
+       0x4afc8003,
+       0x0002f602,
+       0x0c0f04bd,
+       0xa88effb2,
+       0xe5f0501d,
+       0x008f7e01,
+       0x03147e00,
+       0xb23f0f00,
+       0x1d608eff,
+       0x01e5f050,
+       0x00008f7e,
+       0xffb2000f,
+       0x501d9c8e,
+       0x7e01e5f0,
+       0x0f00008f,
+       0x03147e01,
+       0x01fcf000,
+       0xb203f0b6,
+       0x1da88eff,
+       0x01e5f050,
+       0x00008f7e,
+       0xf001acf0,
+       0x008b02a5,
+       0x0c985000,
+       0x0fc4b604,
+       0x9800bcbb,
+       0x0d98000c,
+       0x7e000e01,
+       0xf000013d,
+       0x008b01ac,
+       0x0c985040,
+       0x0fc4b604,
+       0x9800bcbb,
+       0x0d98010c,
+       0x060f9802,
+       0x7e08004e,
+       0xf000013d,
        0xa5f001ac,
-       0x00008b02,
+       0x30008b04,
        0x040c9850,
        0xbb0fc4b6,
        0x0c9800bc,
-       0x010d9800,
-       0x3d7e000e,
-       0xacf00001,
-       0x40008b01,
-       0x040c9850,
-       0xbb0fc4b6,
-       0x0c9800bc,
-       0x020d9801,
-       0x4e060f98,
-       0x3d7e0800,
-       0xacf00001,
-       0x04a5f001,
-       0x5030008b,
-       0xb6040c98,
-       0xbcbb0fc4,
-       0x020c9800,
-       0x98030d98,
-       0x004e080f,
-       0x013d7e02,
-       0x020a7e00,
-       0x0601f400,
-/* 0x05a3: ctx_xfer_post */
-       0x7e0712f4,
-/* 0x05a7: ctx_xfer_done */
-       0x7e000227,
-       0xf80004cf,
+       0x030d9802,
+       0x4e080f98,
+       0x3d7e0200,
+       0x0a7e0001,
+       0x147e0002,
+       0x01f40003,
+       0x1a12f406,
+/* 0x073c: ctx_xfer_post */
+       0x0002277e,
+       0xffb20d0f,
+       0x501da88e,
+       0x7e01e5f0,
+       0x7e00008f,
+/* 0x0753: ctx_xfer_done */
+       0x7e000314,
+       0xf800060d,
+       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 2a0b0f84429928260a3238963a30965abed03f48..fa618066441a12f60f1b27b43ce748362571ac1f 100644 (file)
@@ -29,6 +29,7 @@
 #define GK100 0xe0
 #define GK110 0xf0
 #define GK208 0x108
+#define GM107 0x117
 
 #define NV_PGRAPH_TRAPPED_ADDR                                         0x400704
 #define NV_PGRAPH_TRAPPED_DATA_LO                                      0x400708
@@ -79,7 +80,9 @@
 #define NV_PGRAPH_FECS_MMCTX_MULTI_STRIDE                              0x409718
 #define NV_PGRAPH_FECS_MMCTX_MULTI_MASK                                0x40971c
 #define NV_PGRAPH_FECS_MMCTX_QUEUE                                     0x409720
+#define NV_PGRAPH_FECS_MMIO_BASE                                       0x409724
 #define NV_PGRAPH_FECS_MMIO_CTRL                                       0x409728
+#define NV_PGRAPH_FECS_MMIO_CTRL_BASE_ENABLE                         0x00000001
 #define NV_PGRAPH_FECS_MMIO_RDVAL                                      0x40972c
 #define NV_PGRAPH_FECS_MMIO_WRVAL                                      0x409730
 #define NV_PGRAPH_FECS_MMCTX_LOAD_COUNT                                0x40974c
 #define NV_PGRAPH_GPCX_GPCCS_MYINDEX                                   0x41a618
 #define NV_PGRAPH_GPCX_GPCCS_MMCTX_SAVE_SWBASE                         0x41a700
 #define NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_SWBASE                         0x41a704
+#define NV_PGRAPH_GPCX_GPCCS_MMIO_BASE                                 0x41a724
+#define NV_PGRAPH_GPCX_GPCCS_MMIO_CTRL                                 0x41a728
+#define NV_PGRAPH_GPCX_GPCCS_MMIO_CTRL_BASE_ENABLE                   0x00000001
+#define NV_PGRAPH_GPCX_GPCCS_MMIO_RDVAL                                0x41a72c
+#define NV_PGRAPH_GPCX_GPCCS_MMIO_WRVAL                                0x41a730
 #define NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_COUNT                          0x41a74c
 #if CHIPSET < GK110
 #define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(n)              ((n) * 4 + 0x41a800)
 #define NV_PGRAPH_GPCX_GPCCS_STRAND_CMD_SAVE                         0x00000003
 #define NV_PGRAPH_GPCX_GPCCS_STRAND_CMD_LOAD                         0x00000004
 #define NV_PGRAPH_GPCX_GPCCS_MEM_BASE                                  0x41aa04
+#define NV_PGRAPH_GPCX_GPCCS_TPC_STATUS                                0x41acfc
+
+#define NV_PGRAPH_GPC0_TPC0                                            0x504000
+#define NV_PGRAPH_GPC0_TPC0__SIZE                                      0x000800
+
+#define NV_PGRAPH_GPC0_TPCX_STRAND_INDEX                               0x501d60
+#define NV_PGRAPH_GPC0_TPCX_STRAND_INDEX_ALL                         0x0000003f
+#define NV_PGRAPH_GPC0_TPCX_STRAND_DATA                                0x501d98
+#define NV_PGRAPH_GPC0_TPCX_STRAND_SELECT                              0x501d9c
+#define NV_PGRAPH_GPC0_TPCX_STRAND_CMD                                 0x501da8
+#define NV_PGRAPH_GPC0_TPCX_STRAND_CMD_SEEK                          0x00000001
+#define NV_PGRAPH_GPC0_TPCX_STRAND_CMD_GET_INFO                      0x00000002
+#define NV_PGRAPH_GPC0_TPCX_STRAND_CMD_SAVE                          0x00000003
+#define NV_PGRAPH_GPC0_TPCX_STRAND_CMD_LOAD                          0x00000004
+#define NV_PGRAPH_GPC0_TPCX_STRAND_CMD_ENABLE                        0x0000000c
+#define NV_PGRAPH_GPC0_TPCX_STRAND_CMD_DISABLE                       0x0000000d
+#define NV_PGRAPH_GPC0_TPCX_STRAND_MEM_BASE                            0x501dc4
+
+#define NV_TPC_STRAND_INDEX                                               0x560
+#define NV_TPC_STRAND_CNT                                                 0x570
+#define NV_TPC_STRAND_SAVE_SWBASE                                         0x588
+#define NV_TPC_STRAND_LOAD_SWBASE                                         0x58c
+#define NV_TPC_STRAND_WORDS                                               0x590
 
 #define mmctx_data(r,c) .b32 (((c - 1) << 26) | r)
 #define queue_init      .skip 72 // (2 * 4) + ((8 * 4) * 2)
 #define T_SAVE    7
 #define T_LCHAN   8
 #define T_LCTXH   9
+#define T_STRTPC  10
 
 #if CHIPSET < GK208
 #define imm32(reg,val) /*
index 1dd482e9da7708f85d379d7dd4fc3853e298119c..5606c25e5d02998fc415a5b9705d9a40868f2a10 100644 (file)
@@ -236,7 +236,7 @@ static int
 gf100_gr_set_shader_exceptions(struct nvkm_object *object, u32 mthd,
                               void *pdata, u32 size)
 {
-       struct gf100_gr_priv *priv = (void *)nv_engine(object);
+       struct gf100_gr_priv *priv = (void *)object->engine;
        if (size >= sizeof(u32)) {
                u32 data = *(u32 *)pdata ? 0xffffffff : 0x00000000;
                nv_wr32(priv, 0x419e44, data);
@@ -260,8 +260,8 @@ gf100_gr_90c0_omthds[] = {
 
 struct nvkm_oclass
 gf100_gr_sclass[] = {
-       { 0x902d, &nvkm_object_ofuncs },
-       { 0x9039, &nvkm_object_ofuncs },
+       { FERMI_TWOD_A, &nvkm_object_ofuncs },
+       { FERMI_MEMORY_TO_MEMORY_FORMAT_A, &nvkm_object_ofuncs },
        { FERMI_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
        { FERMI_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
        {}
@@ -1097,12 +1097,26 @@ gf100_gr_intr(struct nvkm_subdev *subdev)
        u32 subc = (addr & 0x00070000) >> 16;
        u32 data = nv_rd32(priv, 0x400708);
        u32 code = nv_rd32(priv, 0x400110);
-       u32 class = nv_rd32(priv, 0x404200 + (subc * 4));
+       u32 class;
        int chid;
 
+       if (nv_device(priv)->card_type < NV_E0 || subc < 4)
+               class = nv_rd32(priv, 0x404200 + (subc * 4));
+       else
+               class = 0x0000;
+
        engctx = nvkm_engctx_get(engine, inst);
        chid   = pfifo->chid(pfifo, engctx);
 
+       if (stat & 0x00000001) {
+               /*
+                * notifier interrupt, only needed for cyclestats
+                * can be safely ignored
+                */
+               nv_wr32(priv, 0x400100, 0x00000001);
+               stat &= ~0x00000001;
+       }
+
        if (stat & 0x00000010) {
                handle = nvkm_handle_get_class(engctx, class);
                if (!handle || nv_call(handle->object, mthd, data)) {
index aeeca1be9cf04eddbd445b5bd999c75ee12c1b1b..8af1a89eda84d13436b0345301a3e767cc710c19 100644 (file)
@@ -124,10 +124,12 @@ void gf100_gr_dtor(struct nvkm_object *);
 int  gf100_gr_init(struct nvkm_object *);
 void gf100_gr_zbc_init(struct gf100_gr_priv *);
 
-int  gk104_gr_fini(struct nvkm_object *, bool);
+int  gk104_gr_ctor(struct nvkm_object *, struct nvkm_object *,
+                    struct nvkm_oclass *, void *data, u32 size,
+                    struct nvkm_object **);
 int  gk104_gr_init(struct nvkm_object *);
 
-int  gk110_gr_fini(struct nvkm_object *, bool);
+int  gm204_gr_init(struct nvkm_object *);
 
 extern struct nvkm_ofuncs gf100_fermi_ofuncs;
 
@@ -136,6 +138,7 @@ extern struct nvkm_omthds gf100_gr_9097_omthds[];
 extern struct nvkm_omthds gf100_gr_90c0_omthds[];
 extern struct nvkm_oclass gf110_gr_sclass[];
 extern struct nvkm_oclass gk110_gr_sclass[];
+extern struct nvkm_oclass gm204_gr_sclass[];
 
 struct gf100_gr_init {
        u32 addr;
@@ -247,4 +250,17 @@ extern const struct gf100_gr_init gk110_gr_init_tex_0[];
 extern const struct gf100_gr_init gk110_gr_init_sm_0[];
 
 extern const struct gf100_gr_init gk208_gr_init_gpc_unk_0[];
+
+extern const struct gf100_gr_init gm107_gr_init_scc_0[];
+extern const struct gf100_gr_init gm107_gr_init_prop_0[];
+extern const struct gf100_gr_init gm107_gr_init_setup_1[];
+extern const struct gf100_gr_init gm107_gr_init_zcull_0[];
+extern const struct gf100_gr_init gm107_gr_init_gpc_unk_1[];
+extern const struct gf100_gr_init gm107_gr_init_tex_0[];
+extern const struct gf100_gr_init gm107_gr_init_l1c_0[];
+extern const struct gf100_gr_init gm107_gr_init_wwdx_0[];
+extern const struct gf100_gr_init gm107_gr_init_cbm_0[];
+void gm107_gr_init_bios(struct gf100_gr_priv *);
+
+extern const struct gf100_gr_pack gm204_gr_pack_mmio[];
 #endif
index 5362c8176e64b886b4c4669270ef79b68c953091..8df73421c78ca9f9e03557489edb1c80d0e3f998 100644 (file)
@@ -32,8 +32,8 @@
 
 static struct nvkm_oclass
 gf108_gr_sclass[] = {
-       { 0x902d, &nvkm_object_ofuncs },
-       { 0x9039, &nvkm_object_ofuncs },
+       { FERMI_TWOD_A, &nvkm_object_ofuncs },
+       { FERMI_MEMORY_TO_MEMORY_FORMAT_A, &nvkm_object_ofuncs },
        { FERMI_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
        { FERMI_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
        { FERMI_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
index 88beb491b7b8651f5287b923270b8f544a2fe36d..ef76e2dd1d31e600469e1f969b97dcff02c40439 100644 (file)
@@ -32,8 +32,8 @@
 
 struct nvkm_oclass
 gf110_gr_sclass[] = {
-       { 0x902d, &nvkm_object_ofuncs },
-       { 0x9039, &nvkm_object_ofuncs },
+       { FERMI_TWOD_A, &nvkm_object_ofuncs },
+       { FERMI_MEMORY_TO_MEMORY_FORMAT_A, &nvkm_object_ofuncs },
        { FERMI_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
        { FERMI_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
        { FERMI_C, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
index 489fdd94b885c375dc160e5ff58a399fad83a70e..46f7844eca7045f3ed71a0af1f8eb6c992337efe 100644 (file)
@@ -34,8 +34,8 @@
 
 static struct nvkm_oclass
 gk104_gr_sclass[] = {
-       { 0x902d, &nvkm_object_ofuncs },
-       { 0xa040, &nvkm_object_ofuncs },
+       { FERMI_TWOD_A, &nvkm_object_ofuncs },
+       { KEPLER_INLINE_TO_MEMORY_A, &nvkm_object_ofuncs },
        { KEPLER_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
        { KEPLER_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
        {}
@@ -310,6 +310,17 @@ gk104_gr_init(struct nvkm_object *object)
        return gf100_gr_init_ctxctl(priv);
 }
 
+int
+gk104_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+             struct nvkm_oclass *oclass, void *data, u32 size,
+             struct nvkm_object **pobject)
+{
+       struct nvkm_pmu *pmu = nvkm_pmu(parent);
+       if (pmu)
+               pmu->pgob(pmu, false);
+       return gf100_gr_ctor(parent, engine, oclass, data, size, pobject);
+}
+
 #include "fuc/hubgk104.fuc3.h"
 
 static struct gf100_gr_ucode
@@ -334,7 +345,7 @@ struct nvkm_oclass *
 gk104_gr_oclass = &(struct gf100_gr_oclass) {
        .base.handle = NV_ENGINE(GR, 0xe4),
        .base.ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = gf100_gr_ctor,
+               .ctor = gk104_gr_ctor,
                .dtor = gf100_gr_dtor,
                .init = gk104_gr_init,
                .fini = _nvkm_gr_fini,
index 78e03ab1608e7306e9d9f300c051a46cfc389c42..f4cd8e5546af477e0cea931f0e4e5661b86b9bd5 100644 (file)
@@ -34,8 +34,8 @@
 
 struct nvkm_oclass
 gk110_gr_sclass[] = {
-       { 0x902d, &nvkm_object_ofuncs },
-       { 0xa140, &nvkm_object_ofuncs },
+       { FERMI_TWOD_A, &nvkm_object_ofuncs },
+       { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs },
        { KEPLER_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
        { KEPLER_COMPUTE_B, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
        {}
@@ -173,43 +173,6 @@ gk110_gr_pack_mmio[] = {
  * PGRAPH engine/subdev functions
  ******************************************************************************/
 
-int
-gk110_gr_fini(struct nvkm_object *object, bool suspend)
-{
-       struct gf100_gr_priv *priv = (void *)object;
-       static const struct {
-               u32 addr;
-               u32 data;
-       } magic[] = {
-               { 0x020520, 0xfffffffc },
-               { 0x020524, 0xfffffffe },
-               { 0x020524, 0xfffffffc },
-               { 0x020524, 0xfffffff8 },
-               { 0x020524, 0xffffffe0 },
-               { 0x020530, 0xfffffffe },
-               { 0x02052c, 0xfffffffa },
-               { 0x02052c, 0xfffffff0 },
-               { 0x02052c, 0xffffffc0 },
-               { 0x02052c, 0xffffff00 },
-               { 0x02052c, 0xfffffc00 },
-               { 0x02052c, 0xfffcfc00 },
-               { 0x02052c, 0xfff0fc00 },
-               { 0x02052c, 0xff80fc00 },
-               { 0x020528, 0xfffffffe },
-               { 0x020528, 0xfffffffc },
-       };
-       int i;
-
-       nv_mask(priv, 0x000200, 0x08001000, 0x00000000);
-       nv_mask(priv, 0x0206b4, 0x00000000, 0x00000000);
-       for (i = 0; i < ARRAY_SIZE(magic); i++) {
-               nv_wr32(priv, magic[i].addr, magic[i].data);
-               nv_wait(priv, magic[i].addr, 0x80000000, 0x00000000);
-       }
-
-       return nvkm_gr_fini(&priv->base, suspend);
-}
-
 #include "fuc/hubgk110.fuc3.h"
 
 struct gf100_gr_ucode
@@ -234,10 +197,10 @@ struct nvkm_oclass *
 gk110_gr_oclass = &(struct gf100_gr_oclass) {
        .base.handle = NV_ENGINE(GR, 0xf0),
        .base.ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = gf100_gr_ctor,
+               .ctor = gk104_gr_ctor,
                .dtor = gf100_gr_dtor,
                .init = gk104_gr_init,
-               .fini = gk110_gr_fini,
+               .fini = _nvkm_gr_fini,
        },
        .cclass = &gk110_grctx_oclass,
        .sclass =  gk110_gr_sclass,
index 5292c5a9a38cf46e84cda8f7db94730d9880f3e8..9ff9eab0ccaff2dd1ab48ef384ac9b10eefe939e 100644 (file)
@@ -102,10 +102,10 @@ struct nvkm_oclass *
 gk110b_gr_oclass = &(struct gf100_gr_oclass) {
        .base.handle = NV_ENGINE(GR, 0xf1),
        .base.ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = gf100_gr_ctor,
+               .ctor = gk104_gr_ctor,
                .dtor = gf100_gr_dtor,
                .init = gk104_gr_init,
-               .fini = gk110_gr_fini,
+               .fini = _nvkm_gr_fini,
        },
        .cclass = &gk110b_grctx_oclass,
        .sclass =  gk110_gr_sclass,
index ae6b853173b6235439c2b70de3264e78b9128b76..85f44a3d5d11604a0e554865af9fb13f6ea2cf64 100644 (file)
 
 static struct nvkm_oclass
 gk208_gr_sclass[] = {
-       { 0x902d, &nvkm_object_ofuncs },
-       { 0xa140, &nvkm_object_ofuncs },
+       { FERMI_TWOD_A, &nvkm_object_ofuncs },
+       { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs },
        { KEPLER_B, &gf100_fermi_ofuncs },
-       { 0xa1c0, &nvkm_object_ofuncs },
+       { KEPLER_COMPUTE_B, &nvkm_object_ofuncs },
        {}
 };
 
@@ -152,43 +152,6 @@ gk208_gr_pack_mmio[] = {
  * PGRAPH engine/subdev functions
  ******************************************************************************/
 
-static int
-gk208_gr_fini(struct nvkm_object *object, bool suspend)
-{
-       struct gf100_gr_priv *priv = (void *)object;
-       static const struct {
-               u32 addr;
-               u32 data;
-       } magic[] = {
-               { 0x020520, 0xfffffffc },
-               { 0x020524, 0xfffffffe },
-               { 0x020524, 0xfffffffc },
-               { 0x020524, 0xfffffff8 },
-               { 0x020524, 0xffffffe0 },
-               { 0x020530, 0xfffffffe },
-               { 0x02052c, 0xfffffffa },
-               { 0x02052c, 0xfffffff0 },
-               { 0x02052c, 0xffffffc0 },
-               { 0x02052c, 0xffffff00 },
-               { 0x02052c, 0xfffffc00 },
-               { 0x02052c, 0xfffcfc00 },
-               { 0x02052c, 0xfff0fc00 },
-               { 0x02052c, 0xff80fc00 },
-               { 0x020528, 0xfffffffe },
-               { 0x020528, 0xfffffffc },
-       };
-       int i;
-
-       nv_mask(priv, 0x000200, 0x08001000, 0x00000000);
-       nv_mask(priv, 0x0206b4, 0x00000000, 0x00000000);
-       for (i = 0; i < ARRAY_SIZE(magic); i++) {
-               nv_wr32(priv, magic[i].addr, magic[i].data);
-               nv_wait(priv, magic[i].addr, 0x80000000, 0x00000000);
-       }
-
-       return nvkm_gr_fini(&priv->base, suspend);
-}
-
 #include "fuc/hubgk208.fuc5.h"
 
 static struct gf100_gr_ucode
@@ -213,10 +176,10 @@ struct nvkm_oclass *
 gk208_gr_oclass = &(struct gf100_gr_oclass) {
        .base.handle = NV_ENGINE(GR, 0x08),
        .base.ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = gf100_gr_ctor,
+               .ctor = gk104_gr_ctor,
                .dtor = gf100_gr_dtor,
                .init = gk104_gr_init,
-               .fini = gk208_gr_fini,
+               .fini = _nvkm_gr_fini,
        },
        .cclass = &gk208_grctx_oclass,
        .sclass =  gk208_gr_sclass,
index 2137555340840572caed8615633b773d3b550e65..40ff5eb9180c097d1dab6907ac77e4f97dfab996 100644 (file)
@@ -26,8 +26,8 @@
 
 static struct nvkm_oclass
 gk20a_gr_sclass[] = {
-       { 0x902d, &nvkm_object_ofuncs },
-       { 0xa040, &nvkm_object_ofuncs },
+       { FERMI_TWOD_A, &nvkm_object_ofuncs },
+       { KEPLER_INLINE_TO_MEMORY_A, &nvkm_object_ofuncs },
        { KEPLER_C, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
        { KEPLER_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
        {}
index 124492b8a2d632248cbcd59d947832c6a093e59b..a5ebd459bc24bc5491e86bc3e9db684afaa3498f 100644 (file)
@@ -35,8 +35,8 @@
 
 static struct nvkm_oclass
 gm107_gr_sclass[] = {
-       { 0x902d, &nvkm_object_ofuncs },
-       { 0xa140, &nvkm_object_ofuncs },
+       { FERMI_TWOD_A, &nvkm_object_ofuncs },
+       { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs },
        { MAXWELL_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
        { MAXWELL_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
        {}
@@ -71,7 +71,7 @@ gm107_gr_init_ds_0[] = {
        {}
 };
 
-static const struct gf100_gr_init
+const struct gf100_gr_init
 gm107_gr_init_scc_0[] = {
        { 0x40803c,   1, 0x04, 0x00000010 },
        {}
@@ -85,14 +85,14 @@ gm107_gr_init_sked_0[] = {
        {}
 };
 
-static const struct gf100_gr_init
+const struct gf100_gr_init
 gm107_gr_init_prop_0[] = {
        { 0x418408,   1, 0x04, 0x00000000 },
        { 0x4184a0,   1, 0x04, 0x00000000 },
        {}
 };
 
-static const struct gf100_gr_init
+const struct gf100_gr_init
 gm107_gr_init_setup_1[] = {
        { 0x4188c8,   2, 0x04, 0x00000000 },
        { 0x4188d0,   1, 0x04, 0x00010000 },
@@ -100,7 +100,7 @@ gm107_gr_init_setup_1[] = {
        {}
 };
 
-static const struct gf100_gr_init
+const struct gf100_gr_init
 gm107_gr_init_zcull_0[] = {
        { 0x418910,   1, 0x04, 0x00010001 },
        { 0x418914,   1, 0x04, 0x00000301 },
@@ -111,7 +111,7 @@ gm107_gr_init_zcull_0[] = {
        {}
 };
 
-static const struct gf100_gr_init
+const struct gf100_gr_init
 gm107_gr_init_gpc_unk_1[] = {
        { 0x418d00,   1, 0x04, 0x00000000 },
        { 0x418f00,   1, 0x04, 0x00000400 },
@@ -134,7 +134,7 @@ gm107_gr_init_tpccs_0[] = {
        {}
 };
 
-static const struct gf100_gr_init
+const struct gf100_gr_init
 gm107_gr_init_tex_0[] = {
        { 0x419ab0,   1, 0x04, 0x00000000 },
        { 0x419ab8,   1, 0x04, 0x000000e7 },
@@ -160,7 +160,7 @@ gm107_gr_init_pe_0[] = {
        {}
 };
 
-static const struct gf100_gr_init
+const struct gf100_gr_init
 gm107_gr_init_l1c_0[] = {
        { 0x419c98,   1, 0x04, 0x00000000 },
        { 0x419cc0,   2, 0x04, 0x00000000 },
@@ -206,14 +206,14 @@ gm107_gr_init_pes_0[] = {
        {}
 };
 
-static const struct gf100_gr_init
+const struct gf100_gr_init
 gm107_gr_init_wwdx_0[] = {
        { 0x41bfd4,   1, 0x04, 0x00800000 },
        { 0x41bfdc,   1, 0x04, 0x00000000 },
        {}
 };
 
-static const struct gf100_gr_init
+const struct gf100_gr_init
 gm107_gr_init_cbm_0[] = {
        { 0x41becc,   1, 0x04, 0x00000000 },
        {}
@@ -291,7 +291,7 @@ gm107_gr_pack_mmio[] = {
  * PGRAPH engine/subdev functions
  ******************************************************************************/
 
-static void
+void
 gm107_gr_init_bios(struct gf100_gr_priv *priv)
 {
        static const struct {
@@ -464,7 +464,7 @@ gm107_gr_oclass = &(struct gf100_gr_oclass) {
        .cclass = &gm107_grctx_oclass,
        .sclass =  gm107_gr_sclass,
        .mmio = gm107_gr_pack_mmio,
-       .fecs.ucode = 0 ? &gm107_gr_fecs_ucode : NULL,
+       .fecs.ucode = &gm107_gr_fecs_ucode,
        .gpccs.ucode = &gm107_gr_gpccs_ucode,
        .ppc_nr = 2,
 }.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c
new file mode 100644 (file)
index 0000000..2f5eadd
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2015 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 "gf100.h"
+#include "ctxgf100.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+struct nvkm_oclass
+gm204_gr_sclass[] = {
+       { FERMI_TWOD_A, &nvkm_object_ofuncs },
+       { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs },
+       { MAXWELL_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+       { MAXWELL_COMPUTE_B, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gm204_gr_init_main_0[] = {
+       { 0x400080,   1, 0x04, 0x003003e2 },
+       { 0x400088,   1, 0x04, 0xe007bfe7 },
+       { 0x40008c,   1, 0x04, 0x00060000 },
+       { 0x400090,   1, 0x04, 0x00000030 },
+       { 0x40013c,   1, 0x04, 0x003901f3 },
+       { 0x400140,   1, 0x04, 0x00000100 },
+       { 0x400144,   1, 0x04, 0x00000000 },
+       { 0x400148,   1, 0x04, 0x00000110 },
+       { 0x400138,   1, 0x04, 0x00000000 },
+       { 0x400130,   2, 0x04, 0x00000000 },
+       { 0x400124,   1, 0x04, 0x00000002 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_gr_init_fe_0[] = {
+       { 0x40415c,   1, 0x04, 0x00000000 },
+       { 0x404170,   1, 0x04, 0x00000000 },
+       { 0x4041b4,   1, 0x04, 0x00000000 },
+       { 0x4041b8,   1, 0x04, 0x00000010 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_gr_init_ds_0[] = {
+       { 0x40583c,   1, 0x04, 0x00000000 },
+       { 0x405844,   1, 0x04, 0x00ffffff },
+       { 0x40584c,   1, 0x04, 0x00000001 },
+       { 0x405850,   1, 0x04, 0x00000000 },
+       { 0x405900,   1, 0x04, 0x00000000 },
+       { 0x405908,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_gr_init_sked_0[] = {
+       { 0x407010,   1, 0x04, 0x00000000 },
+       { 0x407040,   1, 0x04, 0x80440434 },
+       { 0x407048,   1, 0x04, 0x00000008 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_gr_init_tpccs_0[] = {
+       { 0x419d60,   1, 0x04, 0x0000003f },
+       { 0x419d88,   3, 0x04, 0x00000000 },
+       { 0x419dc4,   1, 0x04, 0x00000000 },
+       { 0x419dc8,   1, 0x04, 0x00000501 },
+       { 0x419dd0,   1, 0x04, 0x00000000 },
+       { 0x419dd4,   1, 0x04, 0x00000100 },
+       { 0x419dd8,   1, 0x04, 0x00000001 },
+       { 0x419ddc,   1, 0x04, 0x00000002 },
+       { 0x419de0,   1, 0x04, 0x00000001 },
+       { 0x419de8,   1, 0x04, 0x000000cc },
+       { 0x419dec,   1, 0x04, 0x00000000 },
+       { 0x419df0,   1, 0x04, 0x000000cc },
+       { 0x419df4,   1, 0x04, 0x00000000 },
+       { 0x419d0c,   1, 0x04, 0x00000000 },
+       { 0x419d10,   1, 0x04, 0x00000014 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_gr_init_pe_0[] = {
+       { 0x419900,   1, 0x04, 0x000000ff },
+       { 0x419810,   1, 0x04, 0x00000000 },
+       { 0x41980c,   1, 0x04, 0x00000010 },
+       { 0x419844,   1, 0x04, 0x00000000 },
+       { 0x419838,   1, 0x04, 0x000000ff },
+       { 0x419850,   1, 0x04, 0x00000004 },
+       { 0x419854,   2, 0x04, 0x00000000 },
+       { 0x419894,   3, 0x04, 0x00100401 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_gr_init_sm_0[] = {
+       { 0x419e30,   1, 0x04, 0x000000ff },
+       { 0x419e00,   1, 0x04, 0x00000000 },
+       { 0x419ea0,   1, 0x04, 0x00000000 },
+       { 0x419ee4,   1, 0x04, 0x00000000 },
+       { 0x419ea4,   1, 0x04, 0x00000100 },
+       { 0x419ea8,   1, 0x04, 0x00000000 },
+       { 0x419ee8,   1, 0x04, 0x00000091 },
+       { 0x419eb4,   1, 0x04, 0x00000000 },
+       { 0x419ebc,   2, 0x04, 0x00000000 },
+       { 0x419edc,   1, 0x04, 0x000c1810 },
+       { 0x419ed8,   1, 0x04, 0x00000000 },
+       { 0x419ee0,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_gr_init_l1c_1[] = {
+       { 0x419cf8,   2, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_gr_init_sm_1[] = {
+       { 0x419f74,   1, 0x04, 0x00055155 },
+       { 0x419f80,   4, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_gr_init_l1c_2[] = {
+       { 0x419ccc,   2, 0x04, 0x00000000 },
+       { 0x419c80,   1, 0x04, 0x3f006022 },
+       { 0x419c88,   1, 0x04, 0x00210000 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_gr_init_pes_0[] = {
+       { 0x41be50,   1, 0x04, 0x000000ff },
+       { 0x41be04,   1, 0x04, 0x00000000 },
+       { 0x41be08,   1, 0x04, 0x00000004 },
+       { 0x41be0c,   1, 0x04, 0x00000008 },
+       { 0x41be10,   1, 0x04, 0x2e3b8bc7 },
+       { 0x41be14,   2, 0x04, 0x00000000 },
+       { 0x41be3c,   5, 0x04, 0x00100401 },
+       {}
+};
+
+static const struct gf100_gr_init
+gm204_gr_init_be_0[] = {
+       { 0x408890,   1, 0x04, 0x000000ff },
+       { 0x40880c,   1, 0x04, 0x00000000 },
+       { 0x408850,   1, 0x04, 0x00000004 },
+       { 0x408878,   1, 0x04, 0x01b4201c },
+       { 0x40887c,   1, 0x04, 0x80004c55 },
+       { 0x408880,   1, 0x04, 0x0018c258 },
+       { 0x408884,   1, 0x04, 0x0000160f },
+       { 0x408974,   1, 0x04, 0x000000ff },
+       { 0x408910,   9, 0x04, 0x00000000 },
+       { 0x408950,   1, 0x04, 0x00000000 },
+       { 0x408954,   1, 0x04, 0x0000ffff },
+       { 0x408958,   1, 0x04, 0x00000034 },
+       { 0x40895c,   1, 0x04, 0x84b17403 },
+       { 0x408960,   1, 0x04, 0x04c1884f },
+       { 0x408964,   1, 0x04, 0x04714445 },
+       { 0x408968,   1, 0x04, 0x0280802f },
+       { 0x40896c,   1, 0x04, 0x04304856 },
+       { 0x408970,   1, 0x04, 0x00012800 },
+       { 0x408984,   1, 0x04, 0x00000000 },
+       { 0x408988,   1, 0x04, 0x08040201 },
+       { 0x40898c,   1, 0x04, 0x80402010 },
+       {}
+};
+
+const struct gf100_gr_pack
+gm204_gr_pack_mmio[] = {
+       { gm204_gr_init_main_0 },
+       { gm204_gr_init_fe_0 },
+       { gf100_gr_init_pri_0 },
+       { gf100_gr_init_rstr2d_0 },
+       { gf100_gr_init_pd_0 },
+       { gm204_gr_init_ds_0 },
+       { gm107_gr_init_scc_0 },
+       { gm204_gr_init_sked_0 },
+       { gk110_gr_init_cwd_0 },
+       { gm107_gr_init_prop_0 },
+       { gk208_gr_init_gpc_unk_0 },
+       { gf100_gr_init_setup_0 },
+       { gf100_gr_init_crstr_0 },
+       { gm107_gr_init_setup_1 },
+       { gm107_gr_init_zcull_0 },
+       { gf100_gr_init_gpm_0 },
+       { gm107_gr_init_gpc_unk_1 },
+       { gf100_gr_init_gcc_0 },
+       { gm204_gr_init_tpccs_0 },
+       { gm107_gr_init_tex_0 },
+       { gm204_gr_init_pe_0 },
+       { gm107_gr_init_l1c_0 },
+       { gf100_gr_init_mpc_0 },
+       { gm204_gr_init_sm_0 },
+       { gm204_gr_init_l1c_1 },
+       { gm204_gr_init_sm_1 },
+       { gm204_gr_init_l1c_2 },
+       { gm204_gr_init_pes_0 },
+       { gm107_gr_init_wwdx_0 },
+       { gm107_gr_init_cbm_0 },
+       { gm204_gr_init_be_0 },
+       {}
+};
+
+const struct gf100_gr_pack *
+gm204_gr_data[] = {
+       gm204_gr_pack_mmio,
+       NULL
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+gm204_gr_init_ctxctl(struct gf100_gr_priv *priv)
+{
+       return 0;
+}
+
+int
+gm204_gr_init(struct nvkm_object *object)
+{
+       struct gf100_gr_oclass *oclass = (void *)object->oclass;
+       struct gf100_gr_priv *priv = (void *)object;
+       const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
+       u32 data[TPC_MAX / 8] = {};
+       u8  tpcnr[GPC_MAX];
+       int gpc, tpc, ppc, rop;
+       int ret, i;
+       u32 tmp;
+
+       ret = nvkm_gr_init(&priv->base);
+       if (ret)
+               return ret;
+
+       tmp = nv_rd32(priv, 0x100c80); /*XXX: mask? */
+       nv_wr32(priv, 0x418880, 0x00001000 | (tmp & 0x00000fff));
+       nv_wr32(priv, 0x418890, 0x00000000);
+       nv_wr32(priv, 0x418894, 0x00000000);
+       nv_wr32(priv, 0x4188b4, priv->unk4188b4->addr >> 8);
+       nv_wr32(priv, 0x4188b8, priv->unk4188b8->addr >> 8);
+       nv_mask(priv, 0x4188b0, 0x00040000, 0x00040000);
+
+       /*XXX: belongs in fb */
+       nv_wr32(priv, 0x100cc8, priv->unk4188b4->addr >> 8);
+       nv_wr32(priv, 0x100ccc, priv->unk4188b8->addr >> 8);
+       nv_mask(priv, 0x100cc4, 0x00040000, 0x00040000);
+
+       gf100_gr_mmio(priv, oclass->mmio);
+
+       gm107_gr_init_bios(priv);
+
+       nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
+
+       memset(data, 0x00, sizeof(data));
+       memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+       for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
+               do {
+                       gpc = (gpc + 1) % priv->gpc_nr;
+               } while (!tpcnr[gpc]);
+               tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+               data[i / 8] |= tpc << ((i % 8) * 4);
+       }
+
+       nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
+       nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
+       nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
+       nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
+
+       for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+               nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
+                       priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
+               nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
+                       priv->tpc_total);
+               nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
+       }
+
+       nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
+       nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
+       nv_wr32(priv, GPC_BCAST(0x033c), nv_rd32(priv, 0x100804));
+
+       nv_wr32(priv, 0x400500, 0x00010001);
+       nv_wr32(priv, 0x400100, 0xffffffff);
+       nv_wr32(priv, 0x40013c, 0xffffffff);
+       nv_wr32(priv, 0x400124, 0x00000002);
+       nv_wr32(priv, 0x409c24, 0x000e0000);
+       nv_wr32(priv, 0x405848, 0xc0000000);
+       nv_wr32(priv, 0x40584c, 0x00000001);
+       nv_wr32(priv, 0x404000, 0xc0000000);
+       nv_wr32(priv, 0x404600, 0xc0000000);
+       nv_wr32(priv, 0x408030, 0xc0000000);
+       nv_wr32(priv, 0x404490, 0xc0000000);
+       nv_wr32(priv, 0x406018, 0xc0000000);
+       nv_wr32(priv, 0x407020, 0x40000000);
+       nv_wr32(priv, 0x405840, 0xc0000000);
+       nv_wr32(priv, 0x405844, 0x00ffffff);
+       nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
+
+       for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+       printk(KERN_ERR "ppc %d %d\n", gpc, priv->ppc_nr[gpc]);
+               for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++)
+                       nv_wr32(priv, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000);
+               nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+               nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+               nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+               nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+               for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+                       nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
+                       nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
+                       nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
+                       nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
+                       nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
+                       nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000);
+                       nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe);
+                       nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005);
+               }
+               nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
+               nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
+       }
+
+       for (rop = 0; rop < priv->rop_nr; rop++) {
+               nv_wr32(priv, ROP_UNIT(rop, 0x144), 0x40000000);
+               nv_wr32(priv, ROP_UNIT(rop, 0x070), 0x40000000);
+               nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
+               nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
+       }
+
+       nv_wr32(priv, 0x400108, 0xffffffff);
+       nv_wr32(priv, 0x400138, 0xffffffff);
+       nv_wr32(priv, 0x400118, 0xffffffff);
+       nv_wr32(priv, 0x400130, 0xffffffff);
+       nv_wr32(priv, 0x40011c, 0xffffffff);
+       nv_wr32(priv, 0x400134, 0xffffffff);
+
+       nv_wr32(priv, 0x400054, 0x2c350f63);
+
+       gf100_gr_zbc_init(priv);
+
+       return gm204_gr_init_ctxctl(priv);
+}
+
+struct nvkm_oclass *
+gm204_gr_oclass = &(struct gf100_gr_oclass) {
+       .base.handle = NV_ENGINE(GR, 0x24),
+       .base.ofuncs = &(struct nvkm_ofuncs) {
+               .ctor = gf100_gr_ctor,
+               .dtor = gf100_gr_dtor,
+               .init = gm204_gr_init,
+               .fini = _nvkm_gr_fini,
+       },
+       .cclass = &gm204_grctx_oclass,
+       .sclass =  gm204_gr_sclass,
+       .mmio = gm204_gr_pack_mmio,
+       .ppc_nr = 2,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c
new file mode 100644 (file)
index 0000000..04b9733
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 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 "gf100.h"
+#include "ctxgf100.h"
+
+struct nvkm_oclass *
+gm206_gr_oclass = &(struct gf100_gr_oclass) {
+       .base.handle = NV_ENGINE(GR, 0x26),
+       .base.ofuncs = &(struct nvkm_ofuncs) {
+               .ctor = gf100_gr_ctor,
+               .dtor = gf100_gr_dtor,
+               .init = gm204_gr_init,
+               .fini = _nvkm_gr_fini,
+       },
+       .cclass = &gm206_grctx_oclass,
+       .sclass =  gm204_gr_sclass,
+       .mmio = gm204_gr_pack_mmio,
+       .ppc_nr = 2,
+}.base;
index 1fbd93bbb5610711325e5b5f157b7c6c023ba311..f9d0eb5647fa3224089ba691c7c6c8e16dd35968 100644 (file)
@@ -52,7 +52,7 @@ acpi_read_fast(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
        u32 start = offset & ~0x00000fff;
        u32 fetch = limit - start;
 
-       if (nvbios_extend(bios, limit) > 0) {
+       if (nvbios_extend(bios, limit) >= 0) {
                int ret = nouveau_acpi_get_bios_chunk(bios->data, start, fetch);
                if (ret == fetch)
                        return fetch;
@@ -73,7 +73,7 @@ acpi_read_slow(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
        u32 start = offset & ~0xfff;
        u32 fetch = 0;
 
-       if (nvbios_extend(bios, limit) > 0) {
+       if (nvbios_extend(bios, limit) >= 0) {
                while (start + fetch < limit) {
                        int ret = nouveau_acpi_get_bios_chunk(bios->data,
                                                              start + fetch,
index b8853bf16b23ed9e9287f02e29e1c70ddb2e81c6..7622b41619a07dd7e72a25c1b2eaa089db4af286 100644 (file)
@@ -29,7 +29,7 @@ struct nvkm_hwsq {
        u32 data;
        struct {
                u8 data[512];
-               u8 size;
+               u16 size;
        } c;
 };
 
index 3394a5ea8a9fb62719b630b55162a48dda22b34d..ebf709c27e3a0fe7cba35423dd5bbc92b9165188 100644 (file)
@@ -11,17 +11,34 @@ struct hwsq {
 struct hwsq_reg {
        int sequence;
        bool force;
-       u32 addr[2];
+       u32 addr;
+       u32 stride; /* in bytes */
+       u32 mask;
        u32 data;
 };
 
+static inline struct hwsq_reg
+hwsq_stride(u32 addr, u32 stride, u32 mask)
+{
+       return (struct hwsq_reg) {
+               .sequence = 0,
+               .force = 0,
+               .addr = addr,
+               .stride = stride,
+               .mask = mask,
+               .data = 0xdeadbeef,
+       };
+}
+
 static inline struct hwsq_reg
 hwsq_reg2(u32 addr1, u32 addr2)
 {
        return (struct hwsq_reg) {
                .sequence = 0,
                .force = 0,
-               .addr = { addr1, addr2 },
+               .addr = addr1,
+               .stride = addr2 - addr1,
+               .mask = 0x3,
                .data = 0xdeadbeef,
        };
 }
@@ -29,7 +46,14 @@ hwsq_reg2(u32 addr1, u32 addr2)
 static inline struct hwsq_reg
 hwsq_reg(u32 addr)
 {
-       return hwsq_reg2(addr, addr);
+       return (struct hwsq_reg) {
+               .sequence = 0,
+               .force = 0,
+               .addr = addr,
+               .stride = 0,
+               .mask = 0x1,
+               .data = 0xdeadbeef,
+       };
 }
 
 static inline int
@@ -62,18 +86,24 @@ static inline u32
 hwsq_rd32(struct hwsq *ram, struct hwsq_reg *reg)
 {
        if (reg->sequence != ram->sequence)
-               reg->data = nv_rd32(ram->subdev, reg->addr[0]);
+               reg->data = nv_rd32(ram->subdev, reg->addr);
        return reg->data;
 }
 
 static inline void
 hwsq_wr32(struct hwsq *ram, struct hwsq_reg *reg, u32 data)
 {
+       u32 mask, off = 0;
+
        reg->sequence = ram->sequence;
        reg->data = data;
-       if (reg->addr[0] != reg->addr[1])
-               nvkm_hwsq_wr32(ram->hwsq, reg->addr[1], reg->data);
-       nvkm_hwsq_wr32(ram->hwsq, reg->addr[0], reg->data);
+
+       for (mask = reg->mask; mask > 0; mask = (mask & ~1) >> 1) {
+               if (mask & 1)
+                       nvkm_hwsq_wr32(ram->hwsq, reg->addr+off, reg->data);
+
+               off += reg->stride;
+       }
 }
 
 static inline void
index b24a9cc04b738957908f025a20e335afcdd6b616..39a83d82e0cd99e5fe6c3d3a780b75501e39f623 100644 (file)
@@ -184,7 +184,7 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei)
        nv_debug(clk, "setting performance state %d\n", pstatei);
        clk->pstate = pstatei;
 
-       if (pfb->ram->calc) {
+       if (pfb->ram && pfb->ram->calc) {
                int khz = pstate->base.domain[nv_clk_src_mem];
                do {
                        ret = pfb->ram->calc(pfb, khz);
index 14a51a9ff7d0b590e1682bef9d01df77a93d835c..7c63abf11e226fbebd449d98af7d404681cac3bd 100644 (file)
@@ -5,7 +5,7 @@ struct nvkm_pll_vals;
 
 struct nv04_devinit_priv {
        struct nvkm_devinit base;
-       u8 owner;
+       int owner;
 };
 
 int  nv04_devinit_ctor(struct nvkm_object *, struct nvkm_object *,
index 904d601e8a508bba1d440bdf5720eeaab559b1ff..d6be4c6c5408b729af015ce59b95c74cb76c19f2 100644 (file)
@@ -37,7 +37,6 @@ nvkm-y += nvkm/subdev/fb/ramgt215.o
 nvkm-y += nvkm/subdev/fb/rammcp77.o
 nvkm-y += nvkm/subdev/fb/ramgf100.o
 nvkm-y += nvkm/subdev/fb/ramgk104.o
-nvkm-y += nvkm/subdev/fb/ramgk20a.o
 nvkm-y += nvkm/subdev/fb/ramgm107.o
 nvkm-y += nvkm/subdev/fb/sddr2.o
 nvkm-y += nvkm/subdev/fb/sddr3.o
index 16589fa613cd0b4cdd56b52243369661e482bf2d..61fde43dab71dcb73cd3a4aa816cd77ab0629423 100644 (file)
@@ -55,9 +55,11 @@ _nvkm_fb_fini(struct nvkm_object *object, bool suspend)
        struct nvkm_fb *pfb = (void *)object;
        int ret;
 
-       ret = nv_ofuncs(pfb->ram)->fini(nv_object(pfb->ram), suspend);
-       if (ret && suspend)
-               return ret;
+       if (pfb->ram) {
+               ret = nv_ofuncs(pfb->ram)->fini(nv_object(pfb->ram), suspend);
+               if (ret && suspend)
+                       return ret;
+       }
 
        return nvkm_subdev_fini(&pfb->base, suspend);
 }
@@ -72,9 +74,11 @@ _nvkm_fb_init(struct nvkm_object *object)
        if (ret)
                return ret;
 
-       ret = nv_ofuncs(pfb->ram)->init(nv_object(pfb->ram));
-       if (ret)
-               return ret;
+       if (pfb->ram) {
+               ret = nv_ofuncs(pfb->ram)->init(nv_object(pfb->ram));
+               if (ret)
+                       return ret;
+       }
 
        for (i = 0; i < pfb->tile.regions; i++)
                pfb->tile.prog(pfb, i, &pfb->tile.region[i]);
@@ -91,9 +95,12 @@ _nvkm_fb_dtor(struct nvkm_object *object)
        for (i = 0; i < pfb->tile.regions; i++)
                pfb->tile.fini(pfb, i, &pfb->tile.region[i]);
        nvkm_mm_fini(&pfb->tags);
-       nvkm_mm_fini(&pfb->vram);
 
-       nvkm_object_ref(NULL, (struct nvkm_object **)&pfb->ram);
+       if (pfb->ram) {
+               nvkm_mm_fini(&pfb->vram);
+               nvkm_object_ref(NULL, (struct nvkm_object **)&pfb->ram);
+       }
+
        nvkm_subdev_destroy(&pfb->base);
 }
 
@@ -127,6 +134,9 @@ nvkm_fb_create_(struct nvkm_object *parent, struct nvkm_object *engine,
 
        pfb->memtype_valid = impl->memtype;
 
+       if (!impl->ram)
+               return 0;
+
        ret = nvkm_object_ctor(nv_object(pfb), NULL, impl->ram, NULL, 0, &ram);
        if (ret) {
                nv_fatal(pfb, "error detecting memory configuration!!\n");
index 6762847c05e8310874de28213a62d56c655fc92c..a5d7857d3898b1c85a1d43a7f60719538b1711fe 100644 (file)
@@ -65,5 +65,4 @@ gk20a_fb_oclass = &(struct nvkm_fb_impl) {
                .fini = _nvkm_fb_fini,
        },
        .memtype = gf100_fb_memtype_valid,
-       .ram = &gk20a_ram_oclass,
 }.base;
index d82da02daa1f3b8bc48907bba8d2a18b3524221c..485c4b64819a878f3ce21573eb53dcd7ba58be9e 100644 (file)
@@ -32,7 +32,6 @@ extern struct nvkm_oclass gt215_ram_oclass;
 extern struct nvkm_oclass mcp77_ram_oclass;
 extern struct nvkm_oclass gf100_ram_oclass;
 extern struct nvkm_oclass gk104_ram_oclass;
-extern struct nvkm_oclass gk20a_ram_oclass;
 extern struct nvkm_oclass gm107_ram_oclass;
 
 int nvkm_sddr2_calc(struct nvkm_ram *ram);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk20a.c
deleted file mode 100644 (file)
index 5f30db1..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * 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.
- */
-#include "priv.h"
-
-#include <core/device.h>
-
-struct gk20a_mem {
-       struct nvkm_mem base;
-       void *cpuaddr;
-       dma_addr_t handle;
-};
-#define to_gk20a_mem(m) container_of(m, struct gk20a_mem, base)
-
-static void
-gk20a_ram_put(struct nvkm_fb *pfb, struct nvkm_mem **pmem)
-{
-       struct device *dev = nv_device_base(nv_device(pfb));
-       struct gk20a_mem *mem = to_gk20a_mem(*pmem);
-
-       *pmem = NULL;
-       if (unlikely(mem == NULL))
-               return;
-
-       if (likely(mem->cpuaddr))
-               dma_free_coherent(dev, mem->base.size << PAGE_SHIFT,
-                                 mem->cpuaddr, mem->handle);
-
-       kfree(mem->base.pages);
-       kfree(mem);
-}
-
-static int
-gk20a_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin,
-            u32 memtype, struct nvkm_mem **pmem)
-{
-       struct device *dev = nv_device_base(nv_device(pfb));
-       struct gk20a_mem *mem;
-       u32 type = memtype & 0xff;
-       u32 npages, order;
-       int i;
-
-       nv_debug(pfb, "%s: size: %llx align: %x, ncmin: %x\n", __func__, size,
-                align, ncmin);
-
-       npages = size >> PAGE_SHIFT;
-       if (npages == 0)
-               npages = 1;
-
-       if (align == 0)
-               align = PAGE_SIZE;
-       align >>= PAGE_SHIFT;
-
-       /* round alignment to the next power of 2, if needed */
-       order = fls(align);
-       if ((align & (align - 1)) == 0)
-               order--;
-       align = BIT(order);
-
-       /* ensure returned address is correctly aligned */
-       npages = max(align, npages);
-
-       mem = kzalloc(sizeof(*mem), GFP_KERNEL);
-       if (!mem)
-               return -ENOMEM;
-
-       mem->base.size = npages;
-       mem->base.memtype = type;
-
-       mem->base.pages = kzalloc(sizeof(dma_addr_t) * npages, GFP_KERNEL);
-       if (!mem->base.pages) {
-               kfree(mem);
-               return -ENOMEM;
-       }
-
-       *pmem = &mem->base;
-
-       mem->cpuaddr = dma_alloc_coherent(dev, npages << PAGE_SHIFT,
-                                         &mem->handle, GFP_KERNEL);
-       if (!mem->cpuaddr) {
-               nv_error(pfb, "%s: cannot allocate memory!\n", __func__);
-               gk20a_ram_put(pfb, pmem);
-               return -ENOMEM;
-       }
-
-       align <<= PAGE_SHIFT;
-
-       /* alignment check */
-       if (unlikely(mem->handle & (align - 1)))
-               nv_warn(pfb, "memory not aligned as requested: %pad (0x%x)\n",
-                       &mem->handle, align);
-
-       nv_debug(pfb, "alloc size: 0x%x, align: 0x%x, paddr: %pad, vaddr: %p\n",
-                npages << PAGE_SHIFT, align, &mem->handle, mem->cpuaddr);
-
-       for (i = 0; i < npages; i++)
-               mem->base.pages[i] = mem->handle + (PAGE_SIZE * i);
-
-       mem->base.offset = (u64)mem->base.pages[0];
-       return 0;
-}
-
-static int
-gk20a_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-              struct nvkm_oclass *oclass, void *data, u32 datasize,
-              struct nvkm_object **pobject)
-{
-       struct nvkm_ram *ram;
-       int ret;
-
-       ret = nvkm_ram_create(parent, engine, oclass, &ram);
-       *pobject = nv_object(ram);
-       if (ret)
-               return ret;
-       ram->type = NV_MEM_TYPE_STOLEN;
-       ram->size = get_num_physpages() << PAGE_SHIFT;
-
-       ram->get = gk20a_ram_get;
-       ram->put = gk20a_ram_put;
-       return 0;
-}
-
-struct nvkm_oclass
-gk20a_ram_oclass = {
-       .ofuncs = &(struct nvkm_ofuncs) {
-               .ctor = gk20a_ram_ctor,
-               .dtor = _nvkm_ram_dtor,
-               .init = _nvkm_ram_init,
-               .fini = _nvkm_ram_fini,
-       },
-};
index ba19158a5912e740a415480671d1ad375125fa46..0b256aa4960f72eea7e4a6fe8f0450fc72b71faa 100644 (file)
@@ -45,10 +45,8 @@ gm107_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
 
        ret = nvkm_fuse_create(parent, engine, oclass, &priv);
        *pobject = nv_object(priv);
-       if (ret)
-               return ret;
 
-       return 0;
+       return ret;
 }
 
 struct nvkm_oclass
index e6f35abe787973499cd212fc1ee40b40ddc40344..13bb7fc0a569c9c217a3ca5711f49896b176fde0 100644 (file)
@@ -2,3 +2,4 @@ nvkm-y += nvkm/subdev/instmem/base.o
 nvkm-y += nvkm/subdev/instmem/nv04.o
 nvkm-y += nvkm/subdev/instmem/nv40.o
 nvkm-y += nvkm/subdev/instmem/nv50.o
+nvkm-y += nvkm/subdev/instmem/gk20a.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c
new file mode 100644 (file)
index 0000000..dd0994d
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+/*
+ * GK20A does not have dedicated video memory, and to accurately represent this
+ * fact Nouveau will not create a RAM device for it. Therefore its instmem
+ * implementation must be done directly on top of system memory, while providing
+ * coherent read and write operations.
+ *
+ * Instmem can be allocated through two means:
+ * 1) If an IOMMU mapping has been probed, the IOMMU API is used to make memory
+ *    pages contiguous to the GPU. This is the preferred way.
+ * 2) If no IOMMU mapping is probed, the DMA API is used to allocate physically
+ *    contiguous memory.
+ *
+ * In both cases CPU read and writes are performed using PRAMIN (i.e. using the
+ * GPU path) to ensure these operations are coherent for the GPU. This allows us
+ * to use more "relaxed" allocation parameters when using the DMA API, since we
+ * never need a kernel mapping.
+ */
+
+#include <subdev/fb.h>
+#include <core/mm.h>
+#include <core/device.h>
+
+#ifdef __KERNEL__
+#include <linux/dma-attrs.h>
+#include <linux/iommu.h>
+#include <nouveau_platform.h>
+#endif
+
+#include "priv.h"
+
+struct gk20a_instobj_priv {
+       struct nvkm_instobj base;
+       /* Must be second member here - see nouveau_gpuobj_map_vm() */
+       struct nvkm_mem *mem;
+       /* Pointed by mem */
+       struct nvkm_mem _mem;
+};
+
+/*
+ * Used for objects allocated using the DMA API
+ */
+struct gk20a_instobj_dma {
+       struct gk20a_instobj_priv base;
+
+       void *cpuaddr;
+       dma_addr_t handle;
+       struct nvkm_mm_node r;
+};
+
+/*
+ * Used for objects flattened using the IOMMU API
+ */
+struct gk20a_instobj_iommu {
+       struct gk20a_instobj_priv base;
+
+       /* array of base.mem->size pages */
+       struct page *pages[];
+};
+
+struct gk20a_instmem_priv {
+       struct nvkm_instmem base;
+       spinlock_t lock;
+       u64 addr;
+
+       /* Only used if IOMMU if present */
+       struct mutex *mm_mutex;
+       struct nvkm_mm *mm;
+       struct iommu_domain *domain;
+       unsigned long iommu_pgshift;
+
+       /* Only used by DMA API */
+       struct dma_attrs attrs;
+};
+
+/*
+ * Use PRAMIN to read/write data and avoid coherency issues.
+ * PRAMIN uses the GPU path and ensures data will always be coherent.
+ *
+ * A dynamic mapping based solution would be desirable in the future, but
+ * the issue remains of how to maintain coherency efficiently. On ARM it is
+ * not easy (if possible at all?) to create uncached temporary mappings.
+ */
+
+static u32
+gk20a_instobj_rd32(struct nvkm_object *object, u64 offset)
+{
+       struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(object);
+       struct gk20a_instobj_priv *node = (void *)object;
+       unsigned long flags;
+       u64 base = (node->mem->offset + offset) & 0xffffff00000ULL;
+       u64 addr = (node->mem->offset + offset) & 0x000000fffffULL;
+       u32 data;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (unlikely(priv->addr != base)) {
+               nv_wr32(priv, 0x001700, base >> 16);
+               priv->addr = base;
+       }
+       data = nv_rd32(priv, 0x700000 + addr);
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return data;
+}
+
+static void
+gk20a_instobj_wr32(struct nvkm_object *object, u64 offset, u32 data)
+{
+       struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(object);
+       struct gk20a_instobj_priv *node = (void *)object;
+       unsigned long flags;
+       u64 base = (node->mem->offset + offset) & 0xffffff00000ULL;
+       u64 addr = (node->mem->offset + offset) & 0x000000fffffULL;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (unlikely(priv->addr != base)) {
+               nv_wr32(priv, 0x001700, base >> 16);
+               priv->addr = base;
+       }
+       nv_wr32(priv, 0x700000 + addr, data);
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void
+gk20a_instobj_dtor_dma(struct gk20a_instobj_priv *_node)
+{
+       struct gk20a_instobj_dma *node = (void *)_node;
+       struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(node);
+       struct device *dev = nv_device_base(nv_device(priv));
+
+       if (unlikely(!node->cpuaddr))
+               return;
+
+       dma_free_attrs(dev, _node->mem->size << PAGE_SHIFT, node->cpuaddr,
+                      node->handle, &priv->attrs);
+}
+
+static void
+gk20a_instobj_dtor_iommu(struct gk20a_instobj_priv *_node)
+{
+       struct gk20a_instobj_iommu *node = (void *)_node;
+       struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(node);
+       struct nvkm_mm_node *r;
+       int i;
+
+       if (unlikely(list_empty(&_node->mem->regions)))
+               return;
+
+       r = list_first_entry(&_node->mem->regions, struct nvkm_mm_node,
+                            rl_entry);
+
+       /* clear bit 34 to unmap pages */
+       r->offset &= ~BIT(34 - priv->iommu_pgshift);
+
+       /* Unmap pages from GPU address space and free them */
+       for (i = 0; i < _node->mem->size; i++) {
+               iommu_unmap(priv->domain,
+                           (r->offset + i) << priv->iommu_pgshift, PAGE_SIZE);
+               __free_page(node->pages[i]);
+       }
+
+       /* Release area from GPU address space */
+       mutex_lock(priv->mm_mutex);
+       nvkm_mm_free(priv->mm, &r);
+       mutex_unlock(priv->mm_mutex);
+}
+
+static void
+gk20a_instobj_dtor(struct nvkm_object *object)
+{
+       struct gk20a_instobj_priv *node = (void *)object;
+       struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(node);
+
+       if (priv->domain)
+               gk20a_instobj_dtor_iommu(node);
+       else
+               gk20a_instobj_dtor_dma(node);
+
+       nvkm_instobj_destroy(&node->base);
+}
+
+static int
+gk20a_instobj_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine,
+                      struct nvkm_oclass *oclass, u32 npages, u32 align,
+                      struct gk20a_instobj_priv **_node)
+{
+       struct gk20a_instobj_dma *node;
+       struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(parent);
+       struct device *dev = nv_device_base(nv_device(parent));
+       int ret;
+
+       ret = nvkm_instobj_create_(parent, engine, oclass, sizeof(*node),
+                                  (void **)&node);
+       *_node = &node->base;
+       if (ret)
+               return ret;
+
+       node->cpuaddr = dma_alloc_attrs(dev, npages << PAGE_SHIFT,
+                                       &node->handle, GFP_KERNEL,
+                                       &priv->attrs);
+       if (!node->cpuaddr) {
+               nv_error(priv, "cannot allocate DMA memory\n");
+               return -ENOMEM;
+       }
+
+       /* alignment check */
+       if (unlikely(node->handle & (align - 1)))
+               nv_warn(priv, "memory not aligned as requested: %pad (0x%x)\n",
+                       &node->handle, align);
+
+       /* present memory for being mapped using small pages */
+       node->r.type = 12;
+       node->r.offset = node->handle >> 12;
+       node->r.length = (npages << PAGE_SHIFT) >> 12;
+
+       node->base._mem.offset = node->handle;
+
+       INIT_LIST_HEAD(&node->base._mem.regions);
+       list_add_tail(&node->r.rl_entry, &node->base._mem.regions);
+
+       return 0;
+}
+
+static int
+gk20a_instobj_ctor_iommu(struct nvkm_object *parent, struct nvkm_object *engine,
+                        struct nvkm_oclass *oclass, u32 npages, u32 align,
+                        struct gk20a_instobj_priv **_node)
+{
+       struct gk20a_instobj_iommu *node;
+       struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(parent);
+       struct nvkm_mm_node *r;
+       int ret;
+       int i;
+
+       ret = nvkm_instobj_create_(parent, engine, oclass,
+                               sizeof(*node) + sizeof(node->pages[0]) * npages,
+                               (void **)&node);
+       *_node = &node->base;
+       if (ret)
+               return ret;
+
+       /* Allocate backing memory */
+       for (i = 0; i < npages; i++) {
+               struct page *p = alloc_page(GFP_KERNEL);
+
+               if (p == NULL) {
+                       ret = -ENOMEM;
+                       goto free_pages;
+               }
+               node->pages[i] = p;
+       }
+
+       mutex_lock(priv->mm_mutex);
+       /* Reserve area from GPU address space */
+       ret = nvkm_mm_head(priv->mm, 0, 1, npages, npages,
+                          align >> priv->iommu_pgshift, &r);
+       mutex_unlock(priv->mm_mutex);
+       if (ret) {
+               nv_error(priv, "virtual space is full!\n");
+               goto free_pages;
+       }
+
+       /* Map into GPU address space */
+       for (i = 0; i < npages; i++) {
+               struct page *p = node->pages[i];
+               u32 offset = (r->offset + i) << priv->iommu_pgshift;
+
+               ret = iommu_map(priv->domain, offset, page_to_phys(p),
+                               PAGE_SIZE, IOMMU_READ | IOMMU_WRITE);
+               if (ret < 0) {
+                       nv_error(priv, "IOMMU mapping failure: %d\n", ret);
+
+                       while (i-- > 0) {
+                               offset -= PAGE_SIZE;
+                               iommu_unmap(priv->domain, offset, PAGE_SIZE);
+                       }
+                       goto release_area;
+               }
+       }
+
+       /* Bit 34 tells that an address is to be resolved through the IOMMU */
+       r->offset |= BIT(34 - priv->iommu_pgshift);
+
+       node->base._mem.offset = ((u64)r->offset) << priv->iommu_pgshift;
+
+       INIT_LIST_HEAD(&node->base._mem.regions);
+       list_add_tail(&r->rl_entry, &node->base._mem.regions);
+
+       return 0;
+
+release_area:
+       mutex_lock(priv->mm_mutex);
+       nvkm_mm_free(priv->mm, &r);
+       mutex_unlock(priv->mm_mutex);
+
+free_pages:
+       for (i = 0; i < npages && node->pages[i] != NULL; i++)
+               __free_page(node->pages[i]);
+
+       return ret;
+}
+
+static int
+gk20a_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+                  struct nvkm_oclass *oclass, void *data, u32 _size,
+                  struct nvkm_object **pobject)
+{
+       struct nvkm_instobj_args *args = data;
+       struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(parent);
+       struct gk20a_instobj_priv *node;
+       u32 size, align;
+       int ret;
+
+       nv_debug(parent, "%s (%s): size: %x align: %x\n", __func__,
+                priv->domain ? "IOMMU" : "DMA", args->size, args->align);
+
+       /* Round size and align to page bounds */
+       size = max(roundup(args->size, PAGE_SIZE), PAGE_SIZE);
+       align = max(roundup(args->align, PAGE_SIZE), PAGE_SIZE);
+
+       if (priv->domain)
+               ret = gk20a_instobj_ctor_iommu(parent, engine, oclass,
+                                             size >> PAGE_SHIFT, align, &node);
+       else
+               ret = gk20a_instobj_ctor_dma(parent, engine, oclass,
+                                            size >> PAGE_SHIFT, align, &node);
+       *pobject = nv_object(node);
+       if (ret)
+               return ret;
+
+       node->mem = &node->_mem;
+
+       /* present memory for being mapped using small pages */
+       node->mem->size = size >> 12;
+       node->mem->memtype = 0;
+       node->mem->page_shift = 12;
+
+       node->base.addr = node->mem->offset;
+       node->base.size = size;
+
+       nv_debug(parent, "alloc size: 0x%x, align: 0x%x, gaddr: 0x%llx\n",
+                size, align, node->mem->offset);
+
+       return 0;
+}
+
+static struct nvkm_instobj_impl
+gk20a_instobj_oclass = {
+       .base.ofuncs = &(struct nvkm_ofuncs) {
+               .ctor = gk20a_instobj_ctor,
+               .dtor = gk20a_instobj_dtor,
+               .init = _nvkm_instobj_init,
+               .fini = _nvkm_instobj_fini,
+               .rd32 = gk20a_instobj_rd32,
+               .wr32 = gk20a_instobj_wr32,
+       },
+};
+
+
+
+static int
+gk20a_instmem_fini(struct nvkm_object *object, bool suspend)
+{
+       struct gk20a_instmem_priv *priv = (void *)object;
+       priv->addr = ~0ULL;
+       return nvkm_instmem_fini(&priv->base, suspend);
+}
+
+static int
+gk20a_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+                  struct nvkm_oclass *oclass, void *data, u32 size,
+                  struct nvkm_object **pobject)
+{
+       struct gk20a_instmem_priv *priv;
+       struct nouveau_platform_device *plat;
+       int ret;
+
+       ret = nvkm_instmem_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       spin_lock_init(&priv->lock);
+
+       plat = nv_device_to_platform(nv_device(parent));
+       if (plat->gpu->iommu.domain) {
+               priv->domain = plat->gpu->iommu.domain;
+               priv->mm = plat->gpu->iommu.mm;
+               priv->iommu_pgshift = plat->gpu->iommu.pgshift;
+               priv->mm_mutex = &plat->gpu->iommu.mutex;
+
+               nv_info(priv, "using IOMMU\n");
+       } else {
+               init_dma_attrs(&priv->attrs);
+               /*
+                * We will access instmem through PRAMIN and thus do not need a
+                * consistent CPU pointer or kernel mapping
+                */
+               dma_set_attr(DMA_ATTR_NON_CONSISTENT, &priv->attrs);
+               dma_set_attr(DMA_ATTR_WEAK_ORDERING, &priv->attrs);
+               dma_set_attr(DMA_ATTR_WRITE_COMBINE, &priv->attrs);
+               dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &priv->attrs);
+
+               nv_info(priv, "using DMA API\n");
+       }
+
+       return 0;
+}
+
+struct nvkm_oclass *
+gk20a_instmem_oclass = &(struct nvkm_instmem_impl) {
+       .base.handle = NV_SUBDEV(INSTMEM, 0xea),
+       .base.ofuncs = &(struct nvkm_ofuncs) {
+               .ctor = gk20a_instmem_ctor,
+               .dtor = _nvkm_instmem_dtor,
+               .init = _nvkm_instmem_init,
+               .fini = gk20a_instmem_fini,
+       },
+       .instobj = &gk20a_instobj_oclass.base,
+}.base;
index 8e7cc6200d60b6eff06ebd50811d2bbb2969e923..7fb5ea0314cb468ae8a97a1d3f0996f3ad666c77 100644 (file)
@@ -136,7 +136,8 @@ gf100_ltc_dtor(struct nvkm_object *object)
        struct nvkm_ltc_priv *priv = (void *)object;
 
        nvkm_mm_fini(&priv->tags);
-       nvkm_mm_free(&pfb->vram, &priv->tag_ram);
+       if (pfb->ram)
+               nvkm_mm_free(&pfb->vram, &priv->tag_ram);
 
        nvkm_ltc_destroy(priv);
 }
@@ -149,6 +150,12 @@ gf100_ltc_init_tag_ram(struct nvkm_fb *pfb, struct nvkm_ltc_priv *priv)
        u32 tag_size, tag_margin, tag_align;
        int ret;
 
+       /* No VRAM, no tags for now. */
+       if (!pfb->ram) {
+               priv->num_tags = 0;
+               goto mm_init;
+       }
+
        /* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */
        priv->num_tags = (pfb->ram->size >> 17) / 4;
        if (priv->num_tags > (1 << 17))
@@ -183,6 +190,7 @@ gf100_ltc_init_tag_ram(struct nvkm_fb *pfb, struct nvkm_ltc_priv *priv)
                priv->tag_base = tag_base;
        }
 
+mm_init:
        ret = nvkm_mm_init(&priv->tags, 0, priv->num_tags, 1);
        return ret;
 }
index 42cac13ca6293605987a23145984610b8070ab3e..f20e4ca87e17de9c8e4e145990d331288a6f6df1 100644 (file)
@@ -182,7 +182,7 @@ mxm_show_unmatched(struct nvkm_mxm *mxm, u8 *data, void *info)
 {
        u64 desc = *(u64 *)data;
        if ((desc & 0xf0) != 0xf0)
-       nv_info(mxm, "unmatched output device 0x%016llx\n", desc);
+               nv_info(mxm, "unmatched output device 0x%016llx\n", desc);
        return true;
 }
 
index 9a150d52022564a7a9301ab019391addbaaf0507..7081d6a9b95f635c9b36fce612ed7d17d885bd63 100644 (file)
@@ -4,5 +4,6 @@ nvkm-y += nvkm/subdev/pmu/gt215.o
 nvkm-y += nvkm/subdev/pmu/gf100.o
 nvkm-y += nvkm/subdev/pmu/gf110.o
 nvkm-y += nvkm/subdev/pmu/gk104.o
+nvkm-y += nvkm/subdev/pmu/gk110.o
 nvkm-y += nvkm/subdev/pmu/gk208.o
 nvkm-y += nvkm/subdev/pmu/gk20a.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c
new file mode 100644 (file)
index 0000000..89bb94b
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2015 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
+ */
+#define gf110_pmu_code gk110_pmu_code
+#define gf110_pmu_data gk110_pmu_data
+#include "priv.h"
+#include "fuc/gf110.fuc4.h"
+
+#include <subdev/timer.h>
+
+void
+gk110_pmu_pgob(struct nvkm_pmu *pmu, bool enable)
+{
+       static const struct {
+               u32 addr;
+               u32 data;
+       } magic[] = {
+               { 0x020520, 0xfffffffc },
+               { 0x020524, 0xfffffffe },
+               { 0x020524, 0xfffffffc },
+               { 0x020524, 0xfffffff8 },
+               { 0x020524, 0xffffffe0 },
+               { 0x020530, 0xfffffffe },
+               { 0x02052c, 0xfffffffa },
+               { 0x02052c, 0xfffffff0 },
+               { 0x02052c, 0xffffffc0 },
+               { 0x02052c, 0xffffff00 },
+               { 0x02052c, 0xfffffc00 },
+               { 0x02052c, 0xfffcfc00 },
+               { 0x02052c, 0xfff0fc00 },
+               { 0x02052c, 0xff80fc00 },
+               { 0x020528, 0xfffffffe },
+               { 0x020528, 0xfffffffc },
+       };
+       int i;
+
+       nv_mask(pmu, 0x000200, 0x00001000, 0x00000000);
+       nv_rd32(pmu, 0x000200);
+       nv_mask(pmu, 0x000200, 0x08000000, 0x08000000);
+       msleep(50);
+
+       nv_mask(pmu, 0x10a78c, 0x00000002, 0x00000002);
+       nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000001);
+       nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000000);
+
+       nv_mask(pmu, 0x0206b4, 0x00000000, 0x00000000);
+       for (i = 0; i < ARRAY_SIZE(magic); i++) {
+               nv_wr32(pmu, magic[i].addr, magic[i].data);
+               nv_wait(pmu, magic[i].addr, 0x80000000, 0x00000000);
+       }
+
+       nv_mask(pmu, 0x10a78c, 0x00000002, 0x00000000);
+       nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000001);
+       nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000000);
+
+       nv_mask(pmu, 0x000200, 0x08000000, 0x00000000);
+       nv_mask(pmu, 0x000200, 0x00001000, 0x00001000);
+       nv_rd32(pmu, 0x000200);
+}
+
+struct nvkm_oclass *
+gk110_pmu_oclass = &(struct nvkm_pmu_impl) {
+       .base.handle = NV_SUBDEV(PMU, 0xf0),
+       .base.ofuncs = &(struct nvkm_ofuncs) {
+               .ctor = _nvkm_pmu_ctor,
+               .dtor = _nvkm_pmu_dtor,
+               .init = _nvkm_pmu_init,
+               .fini = _nvkm_pmu_fini,
+       },
+       .code.data = gk110_pmu_code,
+       .code.size = sizeof(gk110_pmu_code),
+       .data.data = gk110_pmu_data,
+       .data.size = sizeof(gk110_pmu_data),
+       .pgob = gk110_pmu_pgob,
+}.base;
index 6f9c09af1a49f4d39bb857e874ee307bf07c81ef..b14134ef9ea52455465ebda40703e4d15004ec5b 100644 (file)
@@ -37,4 +37,5 @@ gk208_pmu_oclass = &(struct nvkm_pmu_impl) {
        .code.size = sizeof(gk208_pmu_code),
        .data.data = gk208_pmu_data,
        .data.size = sizeof(gk208_pmu_data),
+       .pgob = gk110_pmu_pgob,
 }.base;
index a49934bbe637ce552686789b313a5204b2656662..594f746e68f2dd288c0a24f8ba3e0d076cce0d21 100644 (file)
@@ -159,7 +159,7 @@ resched:
        nvkm_timer_alarm(priv, 100000000, alarm);
 }
 
-int
+static int
 gk20a_pmu_fini(struct nvkm_object *object, bool suspend)
 {
        struct nvkm_pmu *pmu = (void *)object;
@@ -170,7 +170,7 @@ gk20a_pmu_fini(struct nvkm_object *object, bool suspend)
        return nvkm_subdev_fini(&pmu->base, suspend);
 }
 
-int
+static int
 gk20a_pmu_init(struct nvkm_object *object)
 {
        struct nvkm_pmu *pmu = (void *)object;
@@ -192,7 +192,8 @@ gk20a_pmu_init(struct nvkm_object *object)
        return ret;
 }
 
-struct gk20a_pmu_dvfs_data gk20a_dvfs_data= {
+static struct gk20a_pmu_dvfs_data
+gk20a_dvfs_data= {
        .p_load_target = 70,
        .p_load_max = 90,
        .p_smooth = 1,
index 998410563bfdb1999c6c4885a590c5594f3c1e3a..799e7c8b88f50cc163b45f06731652e5e8a3cd2b 100644 (file)
@@ -40,4 +40,6 @@ struct nvkm_pmu_impl {
 
        void (*pgob)(struct nvkm_pmu *, bool);
 };
+
+void gk110_pmu_pgob(struct nvkm_pmu *, bool);
 #endif
index a94b11f7859d807b7fff43ef6f5efc106a4a9997..b41965c2888d9e43ad57e1c7f74f6e55ee70b288 100644 (file)
@@ -271,18 +271,6 @@ static const struct drm_connector_helper_funcs omap_connector_helper_funcs = {
        .best_encoder = omap_connector_attached_encoder,
 };
 
-/* flush an area of the framebuffer (in case of manual update display that
- * is not automatically flushed)
- */
-void omap_connector_flush(struct drm_connector *connector,
-               int x, int y, int w, int h)
-{
-       struct omap_connector *omap_connector = to_omap_connector(connector);
-
-       /* TODO: enable when supported in dss */
-       VERB("%s: %d,%d, %dx%d", omap_connector->dssdev->name, x, y, w, h);
-}
-
 /* initialize connector */
 struct drm_connector *omap_connector_init(struct drm_device *dev,
                int connector_type, struct omap_dss_device *dssdev,
index b0566a1ca28f3d59c228d9c500b4004ab44895ac..f456544bf300ba89fdea11242afd4656436888dd 100644 (file)
@@ -28,7 +28,6 @@
 
 struct omap_crtc {
        struct drm_crtc base;
-       struct drm_plane *plane;
 
        const char *name;
        int pipe;
@@ -46,7 +45,6 @@ struct omap_crtc {
 
        struct omap_video_timings timings;
        bool enabled;
-       bool full_update;
 
        struct omap_drm_apply apply;
 
@@ -74,8 +72,14 @@ struct omap_crtc {
         * XXX maybe fold into apply_work??
         */
        struct work_struct page_flip_work;
+
+       bool ignore_digit_sync_lost;
 };
 
+/* -----------------------------------------------------------------------------
+ * Helper Functions
+ */
+
 uint32_t pipe2vbl(struct drm_crtc *crtc)
 {
        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
@@ -83,6 +87,22 @@ uint32_t pipe2vbl(struct drm_crtc *crtc)
        return dispc_mgr_get_vsync_irq(omap_crtc->channel);
 }
 
+const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       return &omap_crtc->timings;
+}
+
+enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       return omap_crtc->channel;
+}
+
+/* -----------------------------------------------------------------------------
+ * DSS Manager Functions
+ */
+
 /*
  * Manager-ops, callbacks from output when they need to configure
  * the upstream part of the video pipe.
@@ -122,7 +142,63 @@ static void omap_crtc_start_update(struct omap_overlay_manager *mgr)
 {
 }
 
-static void set_enabled(struct drm_crtc *crtc, bool enable);
+/* Called only from CRTC pre_apply and suspend/resume handlers. */
+static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
+{
+       struct drm_device *dev = crtc->dev;
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       enum omap_channel channel = omap_crtc->channel;
+       struct omap_irq_wait *wait;
+       u32 framedone_irq, vsync_irq;
+       int ret;
+
+       if (dispc_mgr_is_enabled(channel) == enable)
+               return;
+
+       if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
+               /*
+                * Digit output produces some sync lost interrupts during the
+                * first frame when enabling, so we need to ignore those.
+                */
+               omap_crtc->ignore_digit_sync_lost = true;
+       }
+
+       framedone_irq = dispc_mgr_get_framedone_irq(channel);
+       vsync_irq = dispc_mgr_get_vsync_irq(channel);
+
+       if (enable) {
+               wait = omap_irq_wait_init(dev, vsync_irq, 1);
+       } else {
+               /*
+                * When we disable the digit output, we need to wait for
+                * FRAMEDONE to know that DISPC has finished with the output.
+                *
+                * OMAP2/3 does not have FRAMEDONE irq for digit output, and in
+                * that case we need to use vsync interrupt, and wait for both
+                * even and odd frames.
+                */
+
+               if (framedone_irq)
+                       wait = omap_irq_wait_init(dev, framedone_irq, 1);
+               else
+                       wait = omap_irq_wait_init(dev, vsync_irq, 2);
+       }
+
+       dispc_mgr_enable(channel, enable);
+
+       ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
+       if (ret) {
+               dev_err(dev->dev, "%s: timeout waiting for %s\n",
+                               omap_crtc->name, enable ? "enable" : "disable");
+       }
+
+       if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
+               omap_crtc->ignore_digit_sync_lost = false;
+               /* make sure the irq handler sees the value above */
+               mb();
+       }
+}
+
 
 static int omap_crtc_enable(struct omap_overlay_manager *mgr)
 {
@@ -131,7 +207,7 @@ static int omap_crtc_enable(struct omap_overlay_manager *mgr)
        dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info);
        dispc_mgr_set_timings(omap_crtc->channel,
                        &omap_crtc->timings);
-       set_enabled(&omap_crtc->base, true);
+       omap_crtc_set_enabled(&omap_crtc->base, true);
 
        return 0;
 }
@@ -140,7 +216,7 @@ static void omap_crtc_disable(struct omap_overlay_manager *mgr)
 {
        struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
 
-       set_enabled(&omap_crtc->base, false);
+       omap_crtc_set_enabled(&omap_crtc->base, false);
 }
 
 static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
@@ -149,7 +225,6 @@ static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
        struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
        DBG("%s", omap_crtc->name);
        omap_crtc->timings = *timings;
-       omap_crtc->full_update = true;
 }
 
 static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr,
@@ -174,19 +249,201 @@ static void omap_crtc_unregister_framedone_handler(
 }
 
 static const struct dss_mgr_ops mgr_ops = {
-               .connect = omap_crtc_connect,
-               .disconnect = omap_crtc_disconnect,
-               .start_update = omap_crtc_start_update,
-               .enable = omap_crtc_enable,
-               .disable = omap_crtc_disable,
-               .set_timings = omap_crtc_set_timings,
-               .set_lcd_config = omap_crtc_set_lcd_config,
-               .register_framedone_handler = omap_crtc_register_framedone_handler,
-               .unregister_framedone_handler = omap_crtc_unregister_framedone_handler,
+       .connect = omap_crtc_connect,
+       .disconnect = omap_crtc_disconnect,
+       .start_update = omap_crtc_start_update,
+       .enable = omap_crtc_enable,
+       .disable = omap_crtc_disable,
+       .set_timings = omap_crtc_set_timings,
+       .set_lcd_config = omap_crtc_set_lcd_config,
+       .register_framedone_handler = omap_crtc_register_framedone_handler,
+       .unregister_framedone_handler = omap_crtc_unregister_framedone_handler,
 };
 
-/*
- * CRTC funcs:
+/* -----------------------------------------------------------------------------
+ * Apply Logic
+ */
+
+static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
+{
+       struct omap_crtc *omap_crtc =
+                       container_of(irq, struct omap_crtc, error_irq);
+
+       if (omap_crtc->ignore_digit_sync_lost) {
+               irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
+               if (!irqstatus)
+                       return;
+       }
+
+       DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus);
+}
+
+static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
+{
+       struct omap_crtc *omap_crtc =
+                       container_of(irq, struct omap_crtc, apply_irq);
+       struct drm_crtc *crtc = &omap_crtc->base;
+
+       if (!dispc_mgr_go_busy(omap_crtc->channel)) {
+               struct omap_drm_private *priv =
+                               crtc->dev->dev_private;
+               DBG("%s: apply done", omap_crtc->name);
+               __omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq);
+               queue_work(priv->wq, &omap_crtc->apply_work);
+       }
+}
+
+static void apply_worker(struct work_struct *work)
+{
+       struct omap_crtc *omap_crtc =
+                       container_of(work, struct omap_crtc, apply_work);
+       struct drm_crtc *crtc = &omap_crtc->base;
+       struct drm_device *dev = crtc->dev;
+       struct omap_drm_apply *apply, *n;
+       bool need_apply;
+
+       /*
+        * Synchronize everything on mode_config.mutex, to keep
+        * the callbacks and list modification all serialized
+        * with respect to modesetting ioctls from userspace.
+        */
+       drm_modeset_lock(&crtc->mutex, NULL);
+       dispc_runtime_get();
+
+       /*
+        * If we are still pending a previous update, wait.. when the
+        * pending update completes, we get kicked again.
+        */
+       if (omap_crtc->apply_irq.registered)
+               goto out;
+
+       /* finish up previous apply's: */
+       list_for_each_entry_safe(apply, n,
+                       &omap_crtc->pending_applies, pending_node) {
+               apply->post_apply(apply);
+               list_del(&apply->pending_node);
+       }
+
+       need_apply = !list_empty(&omap_crtc->queued_applies);
+
+       /* then handle the next round of of queued apply's: */
+       list_for_each_entry_safe(apply, n,
+                       &omap_crtc->queued_applies, queued_node) {
+               apply->pre_apply(apply);
+               list_del(&apply->queued_node);
+               apply->queued = false;
+               list_add_tail(&apply->pending_node,
+                               &omap_crtc->pending_applies);
+       }
+
+       if (need_apply) {
+               enum omap_channel channel = omap_crtc->channel;
+
+               DBG("%s: GO", omap_crtc->name);
+
+               if (dispc_mgr_is_enabled(channel)) {
+                       dispc_mgr_go(channel);
+                       omap_irq_register(dev, &omap_crtc->apply_irq);
+               } else {
+                       struct omap_drm_private *priv = dev->dev_private;
+                       queue_work(priv->wq, &omap_crtc->apply_work);
+               }
+       }
+
+out:
+       dispc_runtime_put();
+       drm_modeset_unlock(&crtc->mutex);
+}
+
+int omap_crtc_apply(struct drm_crtc *crtc,
+               struct omap_drm_apply *apply)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+
+       WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
+
+       /* no need to queue it again if it is already queued: */
+       if (apply->queued)
+               return 0;
+
+       apply->queued = true;
+       list_add_tail(&apply->queued_node, &omap_crtc->queued_applies);
+
+       /*
+        * If there are no currently pending updates, then go ahead and
+        * kick the worker immediately, otherwise it will run again when
+        * the current update finishes.
+        */
+       if (list_empty(&omap_crtc->pending_applies)) {
+               struct omap_drm_private *priv = crtc->dev->dev_private;
+               queue_work(priv->wq, &omap_crtc->apply_work);
+       }
+
+       return 0;
+}
+
+static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
+{
+       struct omap_crtc *omap_crtc =
+                       container_of(apply, struct omap_crtc, apply);
+       struct drm_crtc *crtc = &omap_crtc->base;
+       struct omap_drm_private *priv = crtc->dev->dev_private;
+       struct drm_encoder *encoder = NULL;
+       unsigned int i;
+
+       DBG("%s: enabled=%d", omap_crtc->name, omap_crtc->enabled);
+
+       for (i = 0; i < priv->num_encoders; i++) {
+               if (priv->encoders[i]->crtc == crtc) {
+                       encoder = priv->encoders[i];
+                       break;
+               }
+       }
+
+       if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder)
+               omap_encoder_set_enabled(omap_crtc->current_encoder, false);
+
+       omap_crtc->current_encoder = encoder;
+
+       if (!omap_crtc->enabled) {
+               if (encoder)
+                       omap_encoder_set_enabled(encoder, false);
+       } else {
+               if (encoder) {
+                       omap_encoder_set_enabled(encoder, false);
+                       omap_encoder_update(encoder, omap_crtc->mgr,
+                                       &omap_crtc->timings);
+                       omap_encoder_set_enabled(encoder, true);
+               }
+       }
+}
+
+static void omap_crtc_post_apply(struct omap_drm_apply *apply)
+{
+       /* nothing needed for post-apply */
+}
+
+void omap_crtc_flush(struct drm_crtc *crtc)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       int loops = 0;
+
+       while (!list_empty(&omap_crtc->pending_applies) ||
+               !list_empty(&omap_crtc->queued_applies) ||
+               omap_crtc->event || omap_crtc->old_fb) {
+
+               if (++loops > 10) {
+                       dev_err(crtc->dev->dev,
+                               "omap_crtc_flush() timeout\n");
+                       break;
+               }
+
+               schedule_timeout_uninterruptible(msecs_to_jiffies(20));
+       }
+}
+
+/* -----------------------------------------------------------------------------
+ * CRTC Functions
  */
 
 static void omap_crtc_destroy(struct drm_crtc *crtc)
@@ -214,17 +471,13 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
 
        if (enabled != omap_crtc->enabled) {
                omap_crtc->enabled = enabled;
-               omap_crtc->full_update = true;
                omap_crtc_apply(crtc, &omap_crtc->apply);
 
-               /* also enable our private plane: */
-               WARN_ON(omap_plane_dpms(omap_crtc->plane, mode));
-
-               /* and any attached overlay planes: */
+               /* Enable/disable all planes associated with the CRTC. */
                for (i = 0; i < priv->num_planes; i++) {
                        struct drm_plane *plane = priv->planes[i];
                        if (plane->crtc == crtc)
-                               WARN_ON(omap_plane_dpms(plane, mode));
+                               WARN_ON(omap_plane_set_enable(plane, enabled));
                }
        }
 }
@@ -256,13 +509,17 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc,
                        mode->type, mode->flags);
 
        copy_timings_drm_to_omap(&omap_crtc->timings, mode);
-       omap_crtc->full_update = true;
 
-       return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb,
-                       0, 0, mode->hdisplay, mode->vdisplay,
-                       x << 16, y << 16,
-                       mode->hdisplay << 16, mode->vdisplay << 16,
-                       NULL, NULL);
+       /*
+        * The primary plane CRTC can be reset if the plane is disabled directly
+        * through the universal plane API. Set it again here.
+        */
+       crtc->primary->crtc = crtc;
+
+       return omap_plane_mode_set(crtc->primary, crtc, crtc->primary->fb,
+                                  0, 0, mode->hdisplay, mode->vdisplay,
+                                  x, y, mode->hdisplay, mode->vdisplay,
+                                  NULL, NULL);
 }
 
 static void omap_crtc_prepare(struct drm_crtc *crtc)
@@ -282,15 +539,13 @@ static void omap_crtc_commit(struct drm_crtc *crtc)
 static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
                struct drm_framebuffer *old_fb)
 {
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       struct drm_plane *plane = omap_crtc->plane;
+       struct drm_plane *plane = crtc->primary;
        struct drm_display_mode *mode = &crtc->mode;
 
        return omap_plane_mode_set(plane, crtc, crtc->primary->fb,
-                       0, 0, mode->hdisplay, mode->vdisplay,
-                       x << 16, y << 16,
-                       mode->hdisplay << 16, mode->vdisplay << 16,
-                       NULL, NULL);
+                                  0, 0, mode->hdisplay, mode->vdisplay,
+                                  x, y, mode->hdisplay, mode->vdisplay,
+                                  NULL, NULL);
 }
 
 static void vblank_cb(void *arg)
@@ -299,6 +554,7 @@ static void vblank_cb(void *arg)
        struct drm_device *dev = crtc->dev;
        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
        unsigned long flags;
+       struct drm_framebuffer *fb;
 
        spin_lock_irqsave(&dev->event_lock, flags);
 
@@ -306,10 +562,15 @@ static void vblank_cb(void *arg)
        if (omap_crtc->event)
                drm_send_vblank_event(dev, omap_crtc->pipe, omap_crtc->event);
 
+       fb = omap_crtc->old_fb;
+
        omap_crtc->event = NULL;
        omap_crtc->old_fb = NULL;
 
        spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       if (fb)
+               drm_framebuffer_unreference(fb);
 }
 
 static void page_flip_worker(struct work_struct *work)
@@ -321,11 +582,10 @@ static void page_flip_worker(struct work_struct *work)
        struct drm_gem_object *bo;
 
        drm_modeset_lock(&crtc->mutex, NULL);
-       omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb,
-                       0, 0, mode->hdisplay, mode->vdisplay,
-                       crtc->x << 16, crtc->y << 16,
-                       mode->hdisplay << 16, mode->vdisplay << 16,
-                       vblank_cb, crtc);
+       omap_plane_mode_set(crtc->primary, crtc, crtc->primary->fb,
+                           0, 0, mode->hdisplay, mode->vdisplay,
+                           crtc->x, crtc->y, mode->hdisplay, mode->vdisplay,
+                           vblank_cb, crtc);
        drm_modeset_unlock(&crtc->mutex);
 
        bo = omap_framebuffer_bo(crtc->primary->fb, 0);
@@ -361,11 +621,12 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
        if (omap_crtc->old_fb) {
                spin_unlock_irqrestore(&dev->event_lock, flags);
                dev_err(dev->dev, "already a pending flip\n");
-               return -EINVAL;
+               return -EBUSY;
        }
 
        omap_crtc->event = event;
        omap_crtc->old_fb = primary->fb = fb;
+       drm_framebuffer_reference(omap_crtc->old_fb);
 
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
@@ -385,7 +646,6 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
 static int omap_crtc_set_property(struct drm_crtc *crtc,
                struct drm_property *property, uint64_t val)
 {
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
        struct omap_drm_private *priv = crtc->dev->dev_private;
 
        if (property == priv->rotation_prop) {
@@ -393,7 +653,7 @@ static int omap_crtc_set_property(struct drm_crtc *crtc,
                                !!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
        }
 
-       return omap_plane_set_property(omap_crtc->plane, property, val);
+       return omap_plane_set_property(crtc->primary, property, val);
 }
 
 static const struct drm_crtc_funcs omap_crtc_funcs = {
@@ -412,256 +672,15 @@ static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
        .mode_set_base = omap_crtc_mode_set_base,
 };
 
-const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc)
-{
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       return &omap_crtc->timings;
-}
-
-enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
-{
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       return omap_crtc->channel;
-}
-
-static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
-{
-       struct omap_crtc *omap_crtc =
-                       container_of(irq, struct omap_crtc, error_irq);
-       struct drm_crtc *crtc = &omap_crtc->base;
-       DRM_ERROR("%s: errors: %08x\n", omap_crtc->name, irqstatus);
-       /* avoid getting in a flood, unregister the irq until next vblank */
-       __omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
-}
-
-static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
-{
-       struct omap_crtc *omap_crtc =
-                       container_of(irq, struct omap_crtc, apply_irq);
-       struct drm_crtc *crtc = &omap_crtc->base;
-
-       if (!omap_crtc->error_irq.registered)
-               __omap_irq_register(crtc->dev, &omap_crtc->error_irq);
-
-       if (!dispc_mgr_go_busy(omap_crtc->channel)) {
-               struct omap_drm_private *priv =
-                               crtc->dev->dev_private;
-               DBG("%s: apply done", omap_crtc->name);
-               __omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq);
-               queue_work(priv->wq, &omap_crtc->apply_work);
-       }
-}
-
-static void apply_worker(struct work_struct *work)
-{
-       struct omap_crtc *omap_crtc =
-                       container_of(work, struct omap_crtc, apply_work);
-       struct drm_crtc *crtc = &omap_crtc->base;
-       struct drm_device *dev = crtc->dev;
-       struct omap_drm_apply *apply, *n;
-       bool need_apply;
-
-       /*
-        * Synchronize everything on mode_config.mutex, to keep
-        * the callbacks and list modification all serialized
-        * with respect to modesetting ioctls from userspace.
-        */
-       drm_modeset_lock(&crtc->mutex, NULL);
-       dispc_runtime_get();
-
-       /*
-        * If we are still pending a previous update, wait.. when the
-        * pending update completes, we get kicked again.
-        */
-       if (omap_crtc->apply_irq.registered)
-               goto out;
-
-       /* finish up previous apply's: */
-       list_for_each_entry_safe(apply, n,
-                       &omap_crtc->pending_applies, pending_node) {
-               apply->post_apply(apply);
-               list_del(&apply->pending_node);
-       }
-
-       need_apply = !list_empty(&omap_crtc->queued_applies);
-
-       /* then handle the next round of of queued apply's: */
-       list_for_each_entry_safe(apply, n,
-                       &omap_crtc->queued_applies, queued_node) {
-               apply->pre_apply(apply);
-               list_del(&apply->queued_node);
-               apply->queued = false;
-               list_add_tail(&apply->pending_node,
-                               &omap_crtc->pending_applies);
-       }
-
-       if (need_apply) {
-               enum omap_channel channel = omap_crtc->channel;
-
-               DBG("%s: GO", omap_crtc->name);
-
-               if (dispc_mgr_is_enabled(channel)) {
-                       omap_irq_register(dev, &omap_crtc->apply_irq);
-                       dispc_mgr_go(channel);
-               } else {
-                       struct omap_drm_private *priv = dev->dev_private;
-                       queue_work(priv->wq, &omap_crtc->apply_work);
-               }
-       }
-
-out:
-       dispc_runtime_put();
-       drm_modeset_unlock(&crtc->mutex);
-}
-
-int omap_crtc_apply(struct drm_crtc *crtc,
-               struct omap_drm_apply *apply)
-{
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-
-       WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
-
-       /* no need to queue it again if it is already queued: */
-       if (apply->queued)
-               return 0;
-
-       apply->queued = true;
-       list_add_tail(&apply->queued_node, &omap_crtc->queued_applies);
-
-       /*
-        * If there are no currently pending updates, then go ahead and
-        * kick the worker immediately, otherwise it will run again when
-        * the current update finishes.
-        */
-       if (list_empty(&omap_crtc->pending_applies)) {
-               struct omap_drm_private *priv = crtc->dev->dev_private;
-               queue_work(priv->wq, &omap_crtc->apply_work);
-       }
-
-       return 0;
-}
-
-/* called only from apply */
-static void set_enabled(struct drm_crtc *crtc, bool enable)
-{
-       struct drm_device *dev = crtc->dev;
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       enum omap_channel channel = omap_crtc->channel;
-       struct omap_irq_wait *wait;
-       u32 framedone_irq, vsync_irq;
-       int ret;
-
-       if (dispc_mgr_is_enabled(channel) == enable)
-               return;
-
-       /*
-        * Digit output produces some sync lost interrupts during the first
-        * frame when enabling, so we need to ignore those.
-        */
-       omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
-
-       framedone_irq = dispc_mgr_get_framedone_irq(channel);
-       vsync_irq = dispc_mgr_get_vsync_irq(channel);
-
-       if (enable) {
-               wait = omap_irq_wait_init(dev, vsync_irq, 1);
-       } else {
-               /*
-                * When we disable the digit output, we need to wait for
-                * FRAMEDONE to know that DISPC has finished with the output.
-                *
-                * OMAP2/3 does not have FRAMEDONE irq for digit output, and in
-                * that case we need to use vsync interrupt, and wait for both
-                * even and odd frames.
-                */
-
-               if (framedone_irq)
-                       wait = omap_irq_wait_init(dev, framedone_irq, 1);
-               else
-                       wait = omap_irq_wait_init(dev, vsync_irq, 2);
-       }
-
-       dispc_mgr_enable(channel, enable);
-
-       ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
-       if (ret) {
-               dev_err(dev->dev, "%s: timeout waiting for %s\n",
-                               omap_crtc->name, enable ? "enable" : "disable");
-       }
-
-       omap_irq_register(crtc->dev, &omap_crtc->error_irq);
-}
-
-static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
-{
-       struct omap_crtc *omap_crtc =
-                       container_of(apply, struct omap_crtc, apply);
-       struct drm_crtc *crtc = &omap_crtc->base;
-       struct drm_encoder *encoder = NULL;
-
-       DBG("%s: enabled=%d, full=%d", omap_crtc->name,
-                       omap_crtc->enabled, omap_crtc->full_update);
-
-       if (omap_crtc->full_update) {
-               struct omap_drm_private *priv = crtc->dev->dev_private;
-               int i;
-               for (i = 0; i < priv->num_encoders; i++) {
-                       if (priv->encoders[i]->crtc == crtc) {
-                               encoder = priv->encoders[i];
-                               break;
-                       }
-               }
-       }
-
-       if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder)
-               omap_encoder_set_enabled(omap_crtc->current_encoder, false);
-
-       omap_crtc->current_encoder = encoder;
-
-       if (!omap_crtc->enabled) {
-               if (encoder)
-                       omap_encoder_set_enabled(encoder, false);
-       } else {
-               if (encoder) {
-                       omap_encoder_set_enabled(encoder, false);
-                       omap_encoder_update(encoder, omap_crtc->mgr,
-                                       &omap_crtc->timings);
-                       omap_encoder_set_enabled(encoder, true);
-               }
-       }
-
-       omap_crtc->full_update = false;
-}
-
-static void omap_crtc_post_apply(struct omap_drm_apply *apply)
-{
-       /* nothing needed for post-apply */
-}
-
-void omap_crtc_flush(struct drm_crtc *crtc)
-{
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       int loops = 0;
-
-       while (!list_empty(&omap_crtc->pending_applies) ||
-               !list_empty(&omap_crtc->queued_applies) ||
-               omap_crtc->event || omap_crtc->old_fb) {
-
-               if (++loops > 10) {
-                       dev_err(crtc->dev->dev,
-                               "omap_crtc_flush() timeout\n");
-                       break;
-               }
-
-               schedule_timeout_uninterruptible(msecs_to_jiffies(20));
-       }
-}
+/* -----------------------------------------------------------------------------
+ * Init and Cleanup
+ */
 
 static const char *channel_names[] = {
-               [OMAP_DSS_CHANNEL_LCD] = "lcd",
-               [OMAP_DSS_CHANNEL_DIGIT] = "tv",
-               [OMAP_DSS_CHANNEL_LCD2] = "lcd2",
-               [OMAP_DSS_CHANNEL_LCD3] = "lcd3",
+       [OMAP_DSS_CHANNEL_LCD] = "lcd",
+       [OMAP_DSS_CHANNEL_DIGIT] = "tv",
+       [OMAP_DSS_CHANNEL_LCD2] = "lcd2",
+       [OMAP_DSS_CHANNEL_LCD3] = "lcd3",
 };
 
 void omap_crtc_pre_init(void)
@@ -681,12 +700,13 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
        struct drm_crtc *crtc = NULL;
        struct omap_crtc *omap_crtc;
        struct omap_overlay_manager_info *info;
+       int ret;
 
        DBG("%s", channel_names[channel]);
 
        omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
        if (!omap_crtc)
-               goto fail;
+               return NULL;
 
        crtc = &omap_crtc->base;
 
@@ -700,8 +720,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
        omap_crtc->apply.post_apply = omap_crtc_post_apply;
 
        omap_crtc->channel = channel;
-       omap_crtc->plane = plane;
-       omap_crtc->plane->crtc = crtc;
        omap_crtc->name = channel_names[channel];
        omap_crtc->pipe = id;
 
@@ -723,18 +741,18 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
        info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
        info->trans_enabled = false;
 
-       drm_crtc_init(dev, crtc, &omap_crtc_funcs);
+       ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
+                                       &omap_crtc_funcs);
+       if (ret < 0) {
+               kfree(omap_crtc);
+               return NULL;
+       }
+
        drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
 
-       omap_plane_install_properties(omap_crtc->plane, &crtc->base);
+       omap_plane_install_properties(crtc->primary, &crtc->base);
 
        omap_crtcs[channel] = omap_crtc;
 
        return crtc;
-
-fail:
-       if (crtc)
-               omap_crtc_destroy(crtc);
-
-       return NULL;
 }
index 58bcd6ae0255dace4ae845c366af35cf62be4f20..9f32a83ca5078a587fccda89947f2dd9a05be83d 100644 (file)
@@ -148,11 +148,15 @@ struct refill_engine {
 
        bool async;
 
-       wait_queue_head_t wait_for_refill;
+       struct completion compl;
 
        struct list_head idle_node;
 };
 
+struct dmm_platform_data {
+       uint32_t cpu_cache_flags;
+};
+
 struct dmm {
        struct device *dev;
        void __iomem *base;
@@ -183,6 +187,8 @@ struct dmm {
 
        /* allocation list and lock */
        struct list_head alloc_head;
+
+       const struct dmm_platform_data *plat_data;
 };
 
 #endif
index 56c60552abba36bbfcc7572ebe2d986cc548141a..042038e8a662b88647726d11d8fbc77eee3c66d2 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/mm.h>
 #include <linux/time.h>
 #include <linux/list.h>
+#include <linux/completion.h>
 
 #include "omap_dmm_tiler.h"
 #include "omap_dmm_priv.h"
 static struct tcm *containers[TILFMT_NFORMATS];
 static struct dmm *omap_dmm;
 
+#if defined(CONFIG_OF)
+static const struct of_device_id dmm_of_match[];
+#endif
+
 /* global spinlock for protecting lists */
 static DEFINE_SPINLOCK(list_lock);
 
@@ -58,19 +63,19 @@ static const struct {
        uint32_t slot_w;        /* width of each slot (in pixels) */
        uint32_t slot_h;        /* height of each slot (in pixels) */
 } geom[TILFMT_NFORMATS] = {
-               [TILFMT_8BIT]  = GEOM(0, 0, 1),
-               [TILFMT_16BIT] = GEOM(0, 1, 2),
-               [TILFMT_32BIT] = GEOM(1, 1, 4),
-               [TILFMT_PAGE]  = GEOM(SLOT_WIDTH_BITS, SLOT_HEIGHT_BITS, 1),
+       [TILFMT_8BIT]  = GEOM(0, 0, 1),
+       [TILFMT_16BIT] = GEOM(0, 1, 2),
+       [TILFMT_32BIT] = GEOM(1, 1, 4),
+       [TILFMT_PAGE]  = GEOM(SLOT_WIDTH_BITS, SLOT_HEIGHT_BITS, 1),
 };
 
 
 /* lookup table for registers w/ per-engine instances */
 static const uint32_t reg[][4] = {
-               [PAT_STATUS] = {DMM_PAT_STATUS__0, DMM_PAT_STATUS__1,
-                               DMM_PAT_STATUS__2, DMM_PAT_STATUS__3},
-               [PAT_DESCR]  = {DMM_PAT_DESCR__0, DMM_PAT_DESCR__1,
-                               DMM_PAT_DESCR__2, DMM_PAT_DESCR__3},
+       [PAT_STATUS] = {DMM_PAT_STATUS__0, DMM_PAT_STATUS__1,
+                       DMM_PAT_STATUS__2, DMM_PAT_STATUS__3},
+       [PAT_DESCR]  = {DMM_PAT_DESCR__0, DMM_PAT_DESCR__1,
+                       DMM_PAT_DESCR__2, DMM_PAT_DESCR__3},
 };
 
 /* simple allocator to grab next 16 byte aligned memory from txn */
@@ -142,10 +147,10 @@ static irqreturn_t omap_dmm_irq_handler(int irq, void *arg)
 
        for (i = 0; i < dmm->num_engines; i++) {
                if (status & DMM_IRQSTAT_LST) {
-                       wake_up_interruptible(&dmm->engines[i].wait_for_refill);
-
                        if (dmm->engines[i].async)
                                release_engine(&dmm->engines[i]);
+
+                       complete(&dmm->engines[i].compl);
                }
 
                status >>= 8;
@@ -269,15 +274,17 @@ static int dmm_txn_commit(struct dmm_txn *txn, bool wait)
 
        /* mark whether it is async to denote list management in IRQ handler */
        engine->async = wait ? false : true;
+       reinit_completion(&engine->compl);
+       /* verify that the irq handler sees the 'async' and completion value */
+       smp_mb();
 
        /* kick reload */
        writel(engine->refill_pa,
                dmm->base + reg[PAT_DESCR][engine->id]);
 
        if (wait) {
-               if (wait_event_interruptible_timeout(engine->wait_for_refill,
-                               wait_status(engine, DMM_PATSTATUS_READY) == 0,
-                               msecs_to_jiffies(1)) <= 0) {
+               if (!wait_for_completion_timeout(&engine->compl,
+                               msecs_to_jiffies(1))) {
                        dev_err(dmm->dev, "timed out waiting for done\n");
                        ret = -ETIMEDOUT;
                }
@@ -529,6 +536,11 @@ size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h)
        return round_up(geom[fmt].cpp * w, PAGE_SIZE) * h;
 }
 
+uint32_t tiler_get_cpu_cache_flags(void)
+{
+       return omap_dmm->plat_data->cpu_cache_flags;
+}
+
 bool dmm_is_available(void)
 {
        return omap_dmm ? true : false;
@@ -592,6 +604,18 @@ static int omap_dmm_probe(struct platform_device *dev)
 
        init_waitqueue_head(&omap_dmm->engine_queue);
 
+       if (dev->dev.of_node) {
+               const struct of_device_id *match;
+
+               match = of_match_node(dmm_of_match, dev->dev.of_node);
+               if (!match) {
+                       dev_err(&dev->dev, "failed to find matching device node\n");
+                       return -ENODEV;
+               }
+
+               omap_dmm->plat_data = match->data;
+       }
+
        /* lookup hwmod data - base address and irq */
        mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
        if (!mem) {
@@ -696,7 +720,7 @@ static int omap_dmm_probe(struct platform_device *dev)
                                                (REFILL_BUFFER_SIZE * i);
                omap_dmm->engines[i].refill_pa = omap_dmm->refill_pa +
                                                (REFILL_BUFFER_SIZE * i);
-               init_waitqueue_head(&omap_dmm->engines[i].wait_for_refill);
+               init_completion(&omap_dmm->engines[i].compl);
 
                list_add(&omap_dmm->engines[i].idle_node, &omap_dmm->idle_head);
        }
@@ -941,7 +965,7 @@ error:
 }
 #endif
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int omap_dmm_resume(struct device *dev)
 {
        struct tcm_area area;
@@ -965,16 +989,28 @@ static int omap_dmm_resume(struct device *dev)
 
        return 0;
 }
-
-static const struct dev_pm_ops omap_dmm_pm_ops = {
-       .resume = omap_dmm_resume,
-};
 #endif
 
+static SIMPLE_DEV_PM_OPS(omap_dmm_pm_ops, NULL, omap_dmm_resume);
+
 #if defined(CONFIG_OF)
+static const struct dmm_platform_data dmm_omap4_platform_data = {
+       .cpu_cache_flags = OMAP_BO_WC,
+};
+
+static const struct dmm_platform_data dmm_omap5_platform_data = {
+       .cpu_cache_flags = OMAP_BO_UNCACHED,
+};
+
 static const struct of_device_id dmm_of_match[] = {
-       { .compatible = "ti,omap4-dmm", },
-       { .compatible = "ti,omap5-dmm", },
+       {
+               .compatible = "ti,omap4-dmm",
+               .data = &dmm_omap4_platform_data,
+       },
+       {
+               .compatible = "ti,omap5-dmm",
+               .data = &dmm_omap5_platform_data,
+       },
        {},
 };
 #endif
@@ -986,9 +1022,7 @@ struct platform_driver omap_dmm_driver = {
                .owner = THIS_MODULE,
                .name = DMM_DRIVER_NAME,
                .of_match_table = of_match_ptr(dmm_of_match),
-#ifdef CONFIG_PM
                .pm = &omap_dmm_pm_ops,
-#endif
        },
 };
 
index 4fdd61e54bd28abce8aef29c03e62c6596d31aab..e83c78372db8ea422448d14075cc8c8ac4be1c93 100644 (file)
@@ -106,6 +106,7 @@ uint32_t tiler_stride(enum tiler_fmt fmt, uint32_t orient);
 size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h);
 size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h);
 void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h);
+uint32_t tiler_get_cpu_cache_flags(void);
 bool dmm_is_available(void);
 
 extern struct platform_driver omap_dmm_driver;
index 8241ed9b353c426176df85f19f9d1dff39aec866..94920d47e3b63f0dcd37bb6ee73f127f9049d7eb 100644 (file)
@@ -128,6 +128,29 @@ cleanup:
        return r;
 }
 
+static int omap_modeset_create_crtc(struct drm_device *dev, int id,
+                                   enum omap_channel channel)
+{
+       struct omap_drm_private *priv = dev->dev_private;
+       struct drm_plane *plane;
+       struct drm_crtc *crtc;
+
+       plane = omap_plane_init(dev, id, DRM_PLANE_TYPE_PRIMARY);
+       if (IS_ERR(plane))
+               return PTR_ERR(plane);
+
+       crtc = omap_crtc_init(dev, plane, channel, id);
+
+       BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs));
+       priv->crtcs[id] = crtc;
+       priv->num_crtcs++;
+
+       priv->planes[id] = plane;
+       priv->num_planes++;
+
+       return 0;
+}
+
 static int omap_modeset_init(struct drm_device *dev)
 {
        struct omap_drm_private *priv = dev->dev_private;
@@ -136,6 +159,7 @@ static int omap_modeset_init(struct drm_device *dev)
        int num_mgrs = dss_feat_get_num_mgrs();
        int num_crtcs;
        int i, id = 0;
+       int ret;
 
        drm_mode_config_init(dev);
 
@@ -209,18 +233,13 @@ static int omap_modeset_init(struct drm_device *dev)
                 * allocated crtc, we create a new crtc for it
                 */
                if (!channel_used(dev, channel)) {
-                       struct drm_plane *plane;
-                       struct drm_crtc *crtc;
-
-                       plane = omap_plane_init(dev, id, true);
-                       crtc = omap_crtc_init(dev, plane, channel, id);
-
-                       BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs));
-                       priv->crtcs[id] = crtc;
-                       priv->num_crtcs++;
-
-                       priv->planes[id] = plane;
-                       priv->num_planes++;
+                       ret = omap_modeset_create_crtc(dev, id, channel);
+                       if (ret < 0) {
+                               dev_err(dev->dev,
+                                       "could not create CRTC (channel %u)\n",
+                                       channel);
+                               return ret;
+                       }
 
                        id++;
                }
@@ -234,26 +253,8 @@ static int omap_modeset_init(struct drm_device *dev)
 
                /* find a free manager for this crtc */
                for (i = 0; i < num_mgrs; i++) {
-                       if (!channel_used(dev, i)) {
-                               struct drm_plane *plane;
-                               struct drm_crtc *crtc;
-
-                               plane = omap_plane_init(dev, id, true);
-                               crtc = omap_crtc_init(dev, plane, i, id);
-
-                               BUG_ON(priv->num_crtcs >=
-                                       ARRAY_SIZE(priv->crtcs));
-
-                               priv->crtcs[id] = crtc;
-                               priv->num_crtcs++;
-
-                               priv->planes[id] = plane;
-                               priv->num_planes++;
-
+                       if (!channel_used(dev, i))
                                break;
-                       } else {
-                               continue;
-                       }
                }
 
                if (i == num_mgrs) {
@@ -261,13 +262,24 @@ static int omap_modeset_init(struct drm_device *dev)
                        dev_err(dev->dev, "no managers left for crtc\n");
                        return -ENOMEM;
                }
+
+               ret = omap_modeset_create_crtc(dev, id, i);
+               if (ret < 0) {
+                       dev_err(dev->dev,
+                               "could not create CRTC (channel %u)\n", i);
+                       return ret;
+               }
        }
 
        /*
         * Create normal planes for the remaining overlays:
         */
        for (; id < num_ovls; id++) {
-               struct drm_plane *plane = omap_plane_init(dev, id, false);
+               struct drm_plane *plane;
+
+               plane = omap_plane_init(dev, id, DRM_PLANE_TYPE_OVERLAY);
+               if (IS_ERR(plane))
+                       return PTR_ERR(plane);
 
                BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes));
                priv->planes[priv->num_planes++] = plane;
@@ -286,14 +298,13 @@ static int omap_modeset_init(struct drm_device *dev)
                for (id = 0; id < priv->num_crtcs; id++) {
                        struct drm_crtc *crtc = priv->crtcs[id];
                        enum omap_channel crtc_channel;
-                       enum omap_dss_output_id supported_outputs;
 
                        crtc_channel = omap_crtc_channel(crtc);
-                       supported_outputs =
-                               dss_feat_get_supported_outputs(crtc_channel);
 
-                       if (supported_outputs & output->id)
+                       if (output->dispc_channel == crtc_channel) {
                                encoder->possible_crtcs |= (1 << id);
+                               break;
+                       }
                }
 
                omap_dss_put_device(output);
@@ -480,6 +491,7 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
 
        priv->wq = alloc_ordered_workqueue("omapdrm", 0);
 
+       spin_lock_init(&priv->list_lock);
        INIT_LIST_HEAD(&priv->obj_list);
 
        omap_gem_init(dev);
@@ -519,7 +531,8 @@ static int dev_unload(struct drm_device *dev)
 
        drm_kms_helper_poll_fini(dev);
 
-       omap_fbdev_free(dev);
+       if (priv->fbdev)
+               omap_fbdev_free(dev);
 
        /* flush crtcs so the fbs get released */
        for (i = 0; i < priv->num_crtcs; i++)
@@ -588,9 +601,11 @@ static void dev_lastclose(struct drm_device *dev)
                }
        }
 
-       ret = drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev);
-       if (ret)
-               DBG("failed to restore crtc mode");
+       if (priv->fbdev) {
+               ret = drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev);
+               if (ret)
+                       DBG("failed to restore crtc mode");
+       }
 }
 
 static void dev_preclose(struct drm_device *dev, struct drm_file *file)
@@ -610,74 +625,57 @@ static const struct vm_operations_struct omap_gem_vm_ops = {
 };
 
 static const struct file_operations omapdriver_fops = {
-               .owner = THIS_MODULE,
-               .open = drm_open,
-               .unlocked_ioctl = drm_ioctl,
-               .release = drm_release,
-               .mmap = omap_gem_mmap,
-               .poll = drm_poll,
-               .read = drm_read,
-               .llseek = noop_llseek,
+       .owner = THIS_MODULE,
+       .open = drm_open,
+       .unlocked_ioctl = drm_ioctl,
+       .release = drm_release,
+       .mmap = omap_gem_mmap,
+       .poll = drm_poll,
+       .read = drm_read,
+       .llseek = noop_llseek,
 };
 
 static struct drm_driver omap_drm_driver = {
-               .driver_features =
-                               DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
-               .load = dev_load,
-               .unload = dev_unload,
-               .open = dev_open,
-               .lastclose = dev_lastclose,
-               .preclose = dev_preclose,
-               .postclose = dev_postclose,
-               .set_busid = drm_platform_set_busid,
-               .get_vblank_counter = drm_vblank_count,
-               .enable_vblank = omap_irq_enable_vblank,
-               .disable_vblank = omap_irq_disable_vblank,
-               .irq_preinstall = omap_irq_preinstall,
-               .irq_postinstall = omap_irq_postinstall,
-               .irq_uninstall = omap_irq_uninstall,
-               .irq_handler = omap_irq_handler,
+       .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM
+                        | DRIVER_PRIME,
+       .load = dev_load,
+       .unload = dev_unload,
+       .open = dev_open,
+       .lastclose = dev_lastclose,
+       .preclose = dev_preclose,
+       .postclose = dev_postclose,
+       .set_busid = drm_platform_set_busid,
+       .get_vblank_counter = drm_vblank_count,
+       .enable_vblank = omap_irq_enable_vblank,
+       .disable_vblank = omap_irq_disable_vblank,
+       .irq_preinstall = omap_irq_preinstall,
+       .irq_postinstall = omap_irq_postinstall,
+       .irq_uninstall = omap_irq_uninstall,
+       .irq_handler = omap_irq_handler,
 #ifdef CONFIG_DEBUG_FS
-               .debugfs_init = omap_debugfs_init,
-               .debugfs_cleanup = omap_debugfs_cleanup,
+       .debugfs_init = omap_debugfs_init,
+       .debugfs_cleanup = omap_debugfs_cleanup,
 #endif
-               .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
-               .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
-               .gem_prime_export = omap_gem_prime_export,
-               .gem_prime_import = omap_gem_prime_import,
-               .gem_free_object = omap_gem_free_object,
-               .gem_vm_ops = &omap_gem_vm_ops,
-               .dumb_create = omap_gem_dumb_create,
-               .dumb_map_offset = omap_gem_dumb_map_offset,
-               .dumb_destroy = drm_gem_dumb_destroy,
-               .ioctls = ioctls,
-               .num_ioctls = DRM_OMAP_NUM_IOCTLS,
-               .fops = &omapdriver_fops,
-               .name = DRIVER_NAME,
-               .desc = DRIVER_DESC,
-               .date = DRIVER_DATE,
-               .major = DRIVER_MAJOR,
-               .minor = DRIVER_MINOR,
-               .patchlevel = DRIVER_PATCHLEVEL,
+       .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+       .gem_prime_export = omap_gem_prime_export,
+       .gem_prime_import = omap_gem_prime_import,
+       .gem_free_object = omap_gem_free_object,
+       .gem_vm_ops = &omap_gem_vm_ops,
+       .dumb_create = omap_gem_dumb_create,
+       .dumb_map_offset = omap_gem_dumb_map_offset,
+       .dumb_destroy = drm_gem_dumb_destroy,
+       .ioctls = ioctls,
+       .num_ioctls = DRM_OMAP_NUM_IOCTLS,
+       .fops = &omapdriver_fops,
+       .name = DRIVER_NAME,
+       .desc = DRIVER_DESC,
+       .date = DRIVER_DATE,
+       .major = DRIVER_MAJOR,
+       .minor = DRIVER_MINOR,
+       .patchlevel = DRIVER_PATCHLEVEL,
 };
 
-static int pdev_suspend(struct platform_device *pDevice, pm_message_t state)
-{
-       DBG("");
-       return 0;
-}
-
-static int pdev_resume(struct platform_device *device)
-{
-       DBG("");
-       return 0;
-}
-
-static void pdev_shutdown(struct platform_device *device)
-{
-       DBG("");
-}
-
 static int pdev_probe(struct platform_device *device)
 {
        int r;
@@ -709,24 +707,35 @@ static int pdev_remove(struct platform_device *device)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static const struct dev_pm_ops omapdrm_pm_ops = {
-       .resume = omap_gem_resume,
-};
+#ifdef CONFIG_PM_SLEEP
+static int omap_drm_suspend(struct device *dev)
+{
+       struct drm_device *drm_dev = dev_get_drvdata(dev);
+
+       drm_kms_helper_poll_disable(drm_dev);
+
+       return 0;
+}
+
+static int omap_drm_resume(struct device *dev)
+{
+       struct drm_device *drm_dev = dev_get_drvdata(dev);
+
+       drm_kms_helper_poll_enable(drm_dev);
+
+       return omap_gem_resume(dev);
+}
 #endif
 
+static SIMPLE_DEV_PM_OPS(omapdrm_pm_ops, omap_drm_suspend, omap_drm_resume);
+
 static struct platform_driver pdev = {
-               .driver = {
-                       .name = DRIVER_NAME,
-#ifdef CONFIG_PM
-                       .pm = &omapdrm_pm_ops,
-#endif
-               },
-               .probe = pdev_probe,
-               .remove = pdev_remove,
-               .suspend = pdev_suspend,
-               .resume = pdev_resume,
-               .shutdown = pdev_shutdown,
+       .driver = {
+               .name = DRIVER_NAME,
+               .pm = &omapdrm_pm_ops,
+       },
+       .probe = pdev_probe,
+       .remove = pdev_remove,
 };
 
 static int __init omap_drm_init(void)
index 60e47b33c8017a788669bd604795438d63794648..b31c79f15aede8481af46d62e8342b59aaa62f4c 100644 (file)
@@ -105,6 +105,9 @@ struct omap_drm_private {
 
        struct workqueue_struct *wq;
 
+       /* lock for obj_list below */
+       spinlock_t list_lock;
+
        /* list of GEM objects: */
        struct list_head obj_list;
 
@@ -160,15 +163,15 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 void omap_crtc_flush(struct drm_crtc *crtc);
 
 struct drm_plane *omap_plane_init(struct drm_device *dev,
-               int plane_id, bool private_plane);
-int omap_plane_dpms(struct drm_plane *plane, int mode);
+               int id, enum drm_plane_type type);
+int omap_plane_set_enable(struct drm_plane *plane, bool enable);
 int omap_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,
-               void (*fxn)(void *), void *arg);
+                       struct drm_crtc *crtc, struct drm_framebuffer *fb,
+                       int crtc_x, int crtc_y,
+                       unsigned int crtc_w, unsigned int crtc_h,
+                       unsigned int src_x, unsigned int src_y,
+                       unsigned int src_w, unsigned int src_h,
+                       void (*fxn)(void *), void *arg);
 void omap_plane_install_properties(struct drm_plane *plane,
                struct drm_mode_object *obj);
 int omap_plane_set_property(struct drm_plane *plane,
@@ -186,8 +189,6 @@ struct drm_connector *omap_connector_init(struct drm_device *dev,
                struct drm_encoder *encoder);
 struct drm_encoder *omap_connector_attached_encoder(
                struct drm_connector *connector);
-void omap_connector_flush(struct drm_connector *connector,
-               int x, int y, int w, int h);
 bool omap_connector_get_hdmi_mode(struct drm_connector *connector);
 
 void copy_timings_omap_to_drm(struct drm_display_mode *mode,
@@ -208,8 +209,6 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
                struct omap_drm_window *win, struct omap_overlay_info *info);
 struct drm_connector *omap_framebuffer_get_next_connector(
                struct drm_framebuffer *fb, struct drm_connector *from);
-void omap_framebuffer_flush(struct drm_framebuffer *fb,
-               int x, int y, int w, int h);
 
 void omap_gem_init(struct drm_device *dev);
 void omap_gem_deinit(struct drm_device *dev);
index 2a5cacdc344b621fd182d3e8d053bbc0e227ac60..b2c1a29cc12b4601885da18f4f0cf230f7557f69 100644 (file)
@@ -86,6 +86,7 @@ struct plane {
 
 struct omap_framebuffer {
        struct drm_framebuffer base;
+       int pin_count;
        const struct format *format;
        struct plane planes[4];
 };
@@ -121,18 +122,6 @@ static int omap_framebuffer_dirty(struct drm_framebuffer *fb,
                struct drm_file *file_priv, unsigned flags, unsigned color,
                struct drm_clip_rect *clips, unsigned num_clips)
 {
-       int i;
-
-       drm_modeset_lock_all(fb->dev);
-
-       for (i = 0; i < num_clips; i++) {
-               omap_framebuffer_flush(fb, clips[i].x1, clips[i].y1,
-                                       clips[i].x2 - clips[i].x1,
-                                       clips[i].y2 - clips[i].y1);
-       }
-
-       drm_modeset_unlock_all(fb->dev);
-
        return 0;
 }
 
@@ -261,6 +250,11 @@ int omap_framebuffer_pin(struct drm_framebuffer *fb)
        struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
        int ret, i, n = drm_format_num_planes(fb->pixel_format);
 
+       if (omap_fb->pin_count > 0) {
+               omap_fb->pin_count++;
+               return 0;
+       }
+
        for (i = 0; i < n; i++) {
                struct plane *plane = &omap_fb->planes[i];
                ret = omap_gem_get_paddr(plane->bo, &plane->paddr, true);
@@ -269,6 +263,8 @@ int omap_framebuffer_pin(struct drm_framebuffer *fb)
                omap_gem_dma_sync(plane->bo, DMA_TO_DEVICE);
        }
 
+       omap_fb->pin_count++;
+
        return 0;
 
 fail:
@@ -287,6 +283,11 @@ int omap_framebuffer_unpin(struct drm_framebuffer *fb)
        struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
        int ret, i, n = drm_format_num_planes(fb->pixel_format);
 
+       omap_fb->pin_count--;
+
+       if (omap_fb->pin_count > 0)
+               return 0;
+
        for (i = 0; i < n; i++) {
                struct plane *plane = &omap_fb->planes[i];
                ret = omap_gem_put_paddr(plane->bo);
@@ -336,34 +337,6 @@ struct drm_connector *omap_framebuffer_get_next_connector(
        return NULL;
 }
 
-/* flush an area of the framebuffer (in case of manual update display that
- * is not automatically flushed)
- */
-void omap_framebuffer_flush(struct drm_framebuffer *fb,
-               int x, int y, int w, int h)
-{
-       struct drm_connector *connector = NULL;
-
-       VERB("flush: %d,%d %dx%d, fb=%p", x, y, w, h, fb);
-
-       /* FIXME: This is racy - no protection against modeset config changes. */
-       while ((connector = omap_framebuffer_get_next_connector(fb, connector))) {
-               /* only consider connectors that are part of a chain */
-               if (connector->encoder && connector->encoder->crtc) {
-                       /* TODO: maybe this should propagate thru the crtc who
-                        * could do the coordinate translation..
-                        */
-                       struct drm_crtc *crtc = connector->encoder->crtc;
-                       int cx = max(0, x - crtc->x);
-                       int cy = max(0, y - crtc->y);
-                       int cw = w + (x - crtc->x) - cx;
-                       int ch = h + (y - crtc->y) - cy;
-
-                       omap_connector_flush(connector, cx, cy, cw, ch);
-               }
-       }
-}
-
 #ifdef CONFIG_DEBUG_FS
 void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
 {
@@ -407,7 +380,7 @@ struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
 struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
                struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
 {
-       struct omap_framebuffer *omap_fb;
+       struct omap_framebuffer *omap_fb = NULL;
        struct drm_framebuffer *fb = NULL;
        const struct format *format = NULL;
        int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format);
@@ -450,6 +423,14 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
                        goto fail;
                }
 
+               if (pitch % format->planes[i].stride_bpp != 0) {
+                       dev_err(dev->dev,
+                               "buffer pitch (%d bytes) is not a multiple of pixel size (%d bytes)\n",
+                               pitch, format->planes[i].stride_bpp);
+                       ret = -EINVAL;
+                       goto fail;
+               }
+
                size = pitch * mode_cmd->height / format->planes[i].sub_y;
 
                if (size > (omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i])) {
@@ -478,8 +459,7 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
        return fb;
 
 fail:
-       if (fb)
-               omap_framebuffer_destroy(fb);
+       kfree(omap_fb);
 
        return ERR_PTR(ret);
 }
index d292d24b3a6e673977b9c5f5ebc353bc6c5c18b7..950cd33890922bb8881a63583190322487814f3a 100644 (file)
@@ -42,42 +42,8 @@ struct omap_fbdev {
        struct work_struct work;
 };
 
-static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h);
 static struct drm_fb_helper *get_fb(struct fb_info *fbi);
 
-static ssize_t omap_fbdev_write(struct fb_info *fbi, const char __user *buf,
-               size_t count, loff_t *ppos)
-{
-       ssize_t res;
-
-       res = fb_sys_write(fbi, buf, count, ppos);
-       omap_fbdev_flush(fbi, 0, 0, fbi->var.xres, fbi->var.yres);
-
-       return res;
-}
-
-static void omap_fbdev_fillrect(struct fb_info *fbi,
-               const struct fb_fillrect *rect)
-{
-       sys_fillrect(fbi, rect);
-       omap_fbdev_flush(fbi, rect->dx, rect->dy, rect->width, rect->height);
-}
-
-static void omap_fbdev_copyarea(struct fb_info *fbi,
-               const struct fb_copyarea *area)
-{
-       sys_copyarea(fbi, area);
-       omap_fbdev_flush(fbi, area->dx, area->dy, area->width, area->height);
-}
-
-static void omap_fbdev_imageblit(struct fb_info *fbi,
-               const struct fb_image *image)
-{
-       sys_imageblit(fbi, image);
-       omap_fbdev_flush(fbi, image->dx, image->dy,
-                               image->width, image->height);
-}
-
 static void pan_worker(struct work_struct *work)
 {
        struct omap_fbdev *fbdev = container_of(work, struct omap_fbdev, work);
@@ -121,10 +87,10 @@ static struct fb_ops omap_fb_ops = {
         * basic fbdev ops which write to the framebuffer
         */
        .fb_read = fb_sys_read,
-       .fb_write = omap_fbdev_write,
-       .fb_fillrect = omap_fbdev_fillrect,
-       .fb_copyarea = omap_fbdev_copyarea,
-       .fb_imageblit = omap_fbdev_imageblit,
+       .fb_write = fb_sys_write,
+       .fb_fillrect = sys_fillrect,
+       .fb_copyarea = sys_copyarea,
+       .fb_imageblit = sys_imageblit,
 
        .fb_check_var = drm_fb_helper_check_var,
        .fb_set_par = drm_fb_helper_set_par,
@@ -294,21 +260,6 @@ static struct drm_fb_helper *get_fb(struct fb_info *fbi)
        return fbi->par;
 }
 
-/* flush an area of the framebuffer (in case of manual update display that
- * is not automatically flushed)
- */
-static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h)
-{
-       struct drm_fb_helper *helper = get_fb(fbi);
-
-       if (!helper)
-               return;
-
-       VERB("flush fbdev: %d,%d %dx%d, fbi=%p", x, y, w, h, fbi);
-
-       omap_framebuffer_flush(helper->fb, x, y, w, h);
-}
-
 /* initialize fbdev helper */
 struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev)
 {
index aeb91ed653c9f8d2e410a6b95ed7e194168ef508..e9718b99a8a9f022bdbc2501e9e1005270bc1f6a 100644 (file)
@@ -828,6 +828,7 @@ int omap_gem_put_paddr(struct drm_gem_object *obj)
                                dev_err(obj->dev->dev,
                                        "could not release unmap: %d\n", ret);
                        }
+                       omap_obj->paddr = 0;
                        omap_obj->block = NULL;
                }
        }
@@ -1272,13 +1273,16 @@ unlock:
 void omap_gem_free_object(struct drm_gem_object *obj)
 {
        struct drm_device *dev = obj->dev;
+       struct omap_drm_private *priv = dev->dev_private;
        struct omap_gem_object *omap_obj = to_omap_bo(obj);
 
        evict(obj);
 
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
+       spin_lock(&priv->list_lock);
        list_del(&omap_obj->mm_list);
+       spin_unlock(&priv->list_lock);
 
        drm_gem_free_mmap_offset(obj);
 
@@ -1358,8 +1362,8 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
                /* currently don't allow cached buffers.. there is some caching
                 * stuff that needs to be handled better
                 */
-               flags &= ~(OMAP_BO_CACHED|OMAP_BO_UNCACHED);
-               flags |= OMAP_BO_WC;
+               flags &= ~(OMAP_BO_CACHED|OMAP_BO_WC|OMAP_BO_UNCACHED);
+               flags |= tiler_get_cpu_cache_flags();
 
                /* align dimensions to slot boundaries... */
                tiler_align(gem2fmt(flags),
@@ -1376,7 +1380,9 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
        if (!omap_obj)
                goto fail;
 
+       spin_lock(&priv->list_lock);
        list_add(&omap_obj->mm_list, &priv->obj_list);
+       spin_unlock(&priv->list_lock);
 
        obj = &omap_obj->base;
 
index a2dbfb1737b4583bf5d1b1b82220ee15185ccce8..b46dabd9faf75690c6782b20a7dd0b1c501bc160 100644 (file)
@@ -156,16 +156,16 @@ static int omap_gem_dmabuf_mmap(struct dma_buf *buffer,
 }
 
 static struct dma_buf_ops omap_dmabuf_ops = {
-               .map_dma_buf = omap_gem_map_dma_buf,
-               .unmap_dma_buf = omap_gem_unmap_dma_buf,
-               .release = omap_gem_dmabuf_release,
-               .begin_cpu_access = omap_gem_dmabuf_begin_cpu_access,
-               .end_cpu_access = omap_gem_dmabuf_end_cpu_access,
-               .kmap_atomic = omap_gem_dmabuf_kmap_atomic,
-               .kunmap_atomic = omap_gem_dmabuf_kunmap_atomic,
-               .kmap = omap_gem_dmabuf_kmap,
-               .kunmap = omap_gem_dmabuf_kunmap,
-               .mmap = omap_gem_dmabuf_mmap,
+       .map_dma_buf = omap_gem_map_dma_buf,
+       .unmap_dma_buf = omap_gem_unmap_dma_buf,
+       .release = omap_gem_dmabuf_release,
+       .begin_cpu_access = omap_gem_dmabuf_begin_cpu_access,
+       .end_cpu_access = omap_gem_dmabuf_end_cpu_access,
+       .kmap_atomic = omap_gem_dmabuf_kmap_atomic,
+       .kunmap_atomic = omap_gem_dmabuf_kunmap_atomic,
+       .kmap = omap_gem_dmabuf_kmap,
+       .kunmap = omap_gem_dmabuf_kunmap,
+       .mmap = omap_gem_dmabuf_mmap,
 };
 
 struct dma_buf *omap_gem_prime_export(struct drm_device *dev,
index f035d2bceae7db358427c689b3a1fdd6cde28334..3eb097efc488476e80b691ef4c6e305520b8186e 100644 (file)
@@ -34,7 +34,7 @@ static void omap_irq_update(struct drm_device *dev)
        struct omap_drm_irq *irq;
        uint32_t irqmask = priv->vblank_mask;
 
-       BUG_ON(!spin_is_locked(&list_lock));
+       assert_spin_locked(&list_lock);
 
        list_for_each_entry(irq, &priv->irq_list, node)
                irqmask |= irq->irqmask;
index ee8e2b3a117ef59c183bd4cd63075ea565be98c1..1c6b63f394741595f110adce51c56188f03787ba 100644 (file)
@@ -65,12 +65,16 @@ struct omap_plane {
        struct callback apply_done_cb;
 };
 
-static void unpin_worker(struct drm_flip_work *work, void *val)
+static void omap_plane_unpin_worker(struct drm_flip_work *work, void *val)
 {
        struct omap_plane *omap_plane =
                        container_of(work, struct omap_plane, unpin_work);
        struct drm_device *dev = omap_plane->base.dev;
 
+       /*
+        * omap_framebuffer_pin/unpin are always called from priv->wq,
+        * so there's no need for locking here.
+        */
        omap_framebuffer_unpin(val);
        mutex_lock(&dev->mode_config.mutex);
        drm_framebuffer_unreference(val);
@@ -78,7 +82,8 @@ static void unpin_worker(struct drm_flip_work *work, void *val)
 }
 
 /* update which fb (if any) is pinned for scanout */
-static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb)
+static int omap_plane_update_pin(struct drm_plane *plane,
+                                struct drm_framebuffer *fb)
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
        struct drm_framebuffer *pinned_fb = omap_plane->pinned_fb;
@@ -121,13 +126,12 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
        struct drm_crtc *crtc = plane->crtc;
        enum omap_channel channel;
        bool enabled = omap_plane->enabled && crtc;
-       bool ilace, replication;
        int ret;
 
        DBG("%s, enabled=%d", omap_plane->name, enabled);
 
        /* if fb has changed, pin new fb: */
-       update_pin(plane, enabled ? plane->fb : NULL);
+       omap_plane_update_pin(plane, enabled ? plane->fb : NULL);
 
        if (!enabled) {
                dispc_ovl_enable(omap_plane->id, false);
@@ -145,20 +149,17 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
        DBG("%d,%d %pad %pad", info->pos_x, info->pos_y,
                        &info->paddr, &info->p_uv_addr);
 
-       /* TODO: */
-       ilace = false;
-       replication = false;
+       dispc_ovl_set_channel_out(omap_plane->id, channel);
 
        /* and finally, update omapdss: */
-       ret = dispc_ovl_setup(omap_plane->id, info,
-                       replication, omap_crtc_timings(crtc), false);
+       ret = dispc_ovl_setup(omap_plane->id, info, false,
+                             omap_crtc_timings(crtc), false);
        if (ret) {
                dev_err(dev->dev, "dispc_ovl_setup failed: %d\n", ret);
                return;
        }
 
        dispc_ovl_enable(omap_plane->id, true);
-       dispc_ovl_set_channel_out(omap_plane->id, channel);
 }
 
 static void omap_plane_post_apply(struct omap_drm_apply *apply)
@@ -167,7 +168,6 @@ static void omap_plane_post_apply(struct omap_drm_apply *apply)
                        container_of(apply, struct omap_plane, apply);
        struct drm_plane *plane = &omap_plane->base;
        struct omap_drm_private *priv = plane->dev->dev_private;
-       struct omap_overlay_info *info = &omap_plane->info;
        struct callback cb;
 
        cb = omap_plane->apply_done_cb;
@@ -177,14 +177,9 @@ static void omap_plane_post_apply(struct omap_drm_apply *apply)
 
        if (cb.fxn)
                cb.fxn(cb.arg);
-
-       if (omap_plane->enabled) {
-               omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y,
-                               info->out_width, info->out_height);
-       }
 }
 
-static int apply(struct drm_plane *plane)
+static int omap_plane_apply(struct drm_plane *plane)
 {
        if (plane->crtc) {
                struct omap_plane *omap_plane = to_omap_plane(plane);
@@ -194,12 +189,12 @@ static int apply(struct drm_plane *plane)
 }
 
 int omap_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,
-               void (*fxn)(void *), void *arg)
+                       struct drm_crtc *crtc, struct drm_framebuffer *fb,
+                       int crtc_x, int crtc_y,
+                       unsigned int crtc_w, unsigned int crtc_h,
+                       unsigned int src_x, unsigned int src_y,
+                       unsigned int src_w, unsigned int src_h,
+                       void (*fxn)(void *), void *arg)
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
        struct omap_drm_window *win = &omap_plane->win;
@@ -209,11 +204,10 @@ int omap_plane_mode_set(struct drm_plane *plane,
        win->crtc_w = crtc_w;
        win->crtc_h = crtc_h;
 
-       /* src values are in Q16 fixed point, convert to integer: */
-       win->src_x = src_x >> 16;
-       win->src_y = src_y >> 16;
-       win->src_w = src_w >> 16;
-       win->src_h = src_h >> 16;
+       win->src_x = src_x;
+       win->src_y = src_y;
+       win->src_w = src_w;
+       win->src_h = src_h;
 
        if (fxn) {
                /* omap_crtc should ensure that a new page flip
@@ -225,15 +219,7 @@ int omap_plane_mode_set(struct drm_plane *plane,
                omap_plane->apply_done_cb.arg = arg;
        }
 
-       if (plane->fb)
-               drm_framebuffer_unreference(plane->fb);
-
-       drm_framebuffer_reference(fb);
-
-       plane->fb = fb;
-       plane->crtc = crtc;
-
-       return apply(plane);
+       return omap_plane_apply(plane);
 }
 
 static int omap_plane_update(struct drm_plane *plane,
@@ -254,17 +240,29 @@ static int omap_plane_update(struct drm_plane *plane,
                break;
        }
 
+       /*
+        * We don't need to take a reference to the framebuffer as the DRM core
+        * has already done so for the purpose of setting plane->fb.
+        */
+       plane->fb = fb;
+       plane->crtc = crtc;
+
+       /* src values are in Q16 fixed point, convert to integer: */
        return omap_plane_mode_set(plane, crtc, fb,
                        crtc_x, crtc_y, crtc_w, crtc_h,
-                       src_x, src_y, src_w, src_h,
+                       src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16,
                        NULL, NULL);
 }
 
 static int omap_plane_disable(struct drm_plane *plane)
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
+
        omap_plane->win.rotation = BIT(DRM_ROTATE_0);
-       return omap_plane_dpms(plane, DRM_MODE_DPMS_OFF);
+       omap_plane->info.zorder = plane->type == DRM_PLANE_TYPE_PRIMARY
+                               ? 0 : omap_plane->id;
+
+       return omap_plane_set_enable(plane, false);
 }
 
 static void omap_plane_destroy(struct drm_plane *plane)
@@ -275,7 +273,6 @@ static void omap_plane_destroy(struct drm_plane *plane)
 
        omap_irq_unregister(plane->dev, &omap_plane->error_irq);
 
-       omap_plane_disable(plane);
        drm_plane_cleanup(plane);
 
        drm_flip_work_cleanup(&omap_plane->unpin_work);
@@ -283,18 +280,15 @@ static void omap_plane_destroy(struct drm_plane *plane)
        kfree(omap_plane);
 }
 
-int omap_plane_dpms(struct drm_plane *plane, int mode)
+int omap_plane_set_enable(struct drm_plane *plane, bool enable)
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
-       bool enabled = (mode == DRM_MODE_DPMS_ON);
-       int ret = 0;
 
-       if (enabled != omap_plane->enabled) {
-               omap_plane->enabled = enabled;
-               ret = apply(plane);
-       }
+       if (enable == omap_plane->enabled)
+               return 0;
 
-       return ret;
+       omap_plane->enabled = enable;
+       return omap_plane_apply(plane);
 }
 
 /* helper to install properties which are common to planes and crtcs */
@@ -342,61 +336,63 @@ int omap_plane_set_property(struct drm_plane *plane,
        if (property == priv->rotation_prop) {
                DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val);
                omap_plane->win.rotation = val;
-               ret = apply(plane);
+               ret = omap_plane_apply(plane);
        } else if (property == priv->zorder_prop) {
                DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val);
                omap_plane->info.zorder = val;
-               ret = apply(plane);
+               ret = omap_plane_apply(plane);
        }
 
        return ret;
 }
 
 static const struct drm_plane_funcs omap_plane_funcs = {
-               .update_plane = omap_plane_update,
-               .disable_plane = omap_plane_disable,
-               .destroy = omap_plane_destroy,
-               .set_property = omap_plane_set_property,
+       .update_plane = omap_plane_update,
+       .disable_plane = omap_plane_disable,
+       .destroy = omap_plane_destroy,
+       .set_property = omap_plane_set_property,
 };
 
 static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
 {
        struct omap_plane *omap_plane =
                        container_of(irq, struct omap_plane, error_irq);
-       DRM_ERROR("%s: errors: %08x\n", omap_plane->name, irqstatus);
+       DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_plane->name,
+               irqstatus);
 }
 
 static const char *plane_names[] = {
-               [OMAP_DSS_GFX] = "gfx",
-               [OMAP_DSS_VIDEO1] = "vid1",
-               [OMAP_DSS_VIDEO2] = "vid2",
-               [OMAP_DSS_VIDEO3] = "vid3",
+       [OMAP_DSS_GFX] = "gfx",
+       [OMAP_DSS_VIDEO1] = "vid1",
+       [OMAP_DSS_VIDEO2] = "vid2",
+       [OMAP_DSS_VIDEO3] = "vid3",
 };
 
 static const uint32_t error_irqs[] = {
-               [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW,
-               [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW,
-               [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW,
-               [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW,
+       [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW,
+       [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW,
+       [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW,
+       [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW,
 };
 
 /* initialize plane */
 struct drm_plane *omap_plane_init(struct drm_device *dev,
-               int id, bool private_plane)
+               int id, enum drm_plane_type type)
 {
        struct omap_drm_private *priv = dev->dev_private;
-       struct drm_plane *plane = NULL;
+       struct drm_plane *plane;
        struct omap_plane *omap_plane;
        struct omap_overlay_info *info;
+       int ret;
 
-       DBG("%s: priv=%d", plane_names[id], private_plane);
+       DBG("%s: type=%d", plane_names[id], type);
 
        omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
        if (!omap_plane)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        drm_flip_work_init(&omap_plane->unpin_work,
-                       "unpin", unpin_worker);
+                       "unpin", omap_plane_unpin_worker);
 
        omap_plane->nformats = omap_framebuffer_get_formats(
                        omap_plane->formats, ARRAY_SIZE(omap_plane->formats),
@@ -413,8 +409,11 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
        omap_plane->error_irq.irq = omap_plane_error_irq;
        omap_irq_register(dev, &omap_plane->error_irq);
 
-       drm_plane_init(dev, plane, (1 << priv->num_crtcs) - 1, &omap_plane_funcs,
-                       omap_plane->formats, omap_plane->nformats, private_plane);
+       ret = drm_universal_plane_init(dev, plane, (1 << priv->num_crtcs) - 1,
+                                      &omap_plane_funcs, omap_plane->formats,
+                                      omap_plane->nformats, type);
+       if (ret < 0)
+               goto error;
 
        omap_plane_install_properties(plane, &plane->base);
 
@@ -432,10 +431,15 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
         * TODO add ioctl to give userspace an API to change this.. this
         * will come in a subsequent patch.
         */
-       if (private_plane)
+       if (type == DRM_PLANE_TYPE_PRIMARY)
                omap_plane->info.zorder = 0;
        else
                omap_plane->info.zorder = id;
 
        return plane;
+
+error:
+       omap_irq_unregister(plane->dev, &omap_plane->error_irq);
+       kfree(omap_plane);
+       return NULL;
 }
index d84583776d50609d846e34014a4dc94c76c0a51d..6d64c7bb908bcdaa403f7e7ec68646135ab710b9 100644 (file)
@@ -11,6 +11,7 @@ config DRM_PANEL_SIMPLE
        tristate "support for simple panels"
        depends on OF
        depends on BACKLIGHT_CLASS_DEVICE
+       select VIDEOMODE_HELPERS
        help
          DRM panel driver for dumb panels that need at most a regulator and
          a GPIO to be powered up. Optionally a backlight can be attached so
index 39806c33533901dec7104e12f1d3d9e3ea731c3c..30904a9b2a4cc993d770ccb8c1a27d76296c4961 100644 (file)
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_panel.h>
 
+#include <video/display_timing.h>
+#include <video/videomode.h>
+
 struct panel_desc {
        const struct drm_display_mode *modes;
        unsigned int num_modes;
+       const struct display_timing *timings;
+       unsigned int num_timings;
 
        unsigned int bpc;
 
@@ -94,6 +99,25 @@ static int panel_simple_get_fixed_modes(struct panel_simple *panel)
        if (!panel->desc)
                return 0;
 
+       for (i = 0; i < panel->desc->num_timings; i++) {
+               const struct display_timing *dt = &panel->desc->timings[i];
+               struct videomode vm;
+
+               videomode_from_timing(dt, &vm);
+               mode = drm_mode_create(drm);
+               if (!mode) {
+                       dev_err(drm->dev, "failed to add mode %ux%u\n",
+                               dt->hactive.typ, dt->vactive.typ);
+                       continue;
+               }
+
+               drm_display_mode_from_videomode(&vm, mode);
+               drm_mode_set_name(mode);
+
+               drm_mode_probed_add(connector, mode);
+               num++;
+       }
+
        for (i = 0; i < panel->desc->num_modes; i++) {
                const struct drm_display_mode *m = &panel->desc->modes[i];
 
@@ -226,12 +250,30 @@ static int panel_simple_get_modes(struct drm_panel *panel)
        return num;
 }
 
+static int panel_simple_get_timings(struct drm_panel *panel,
+                                   unsigned int num_timings,
+                                   struct display_timing *timings)
+{
+       struct panel_simple *p = to_panel_simple(panel);
+       unsigned int i;
+
+       if (p->desc->num_timings < num_timings)
+               num_timings = p->desc->num_timings;
+
+       if (timings)
+               for (i = 0; i < num_timings; i++)
+                       timings[i] = p->desc->timings[i];
+
+       return p->desc->num_timings;
+}
+
 static const struct drm_panel_funcs panel_simple_funcs = {
        .disable = panel_simple_disable,
        .unprepare = panel_simple_unprepare,
        .prepare = panel_simple_prepare,
        .enable = panel_simple_enable,
        .get_modes = panel_simple_get_modes,
+       .get_timings = panel_simple_get_timings,
 };
 
 static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
@@ -327,6 +369,31 @@ static void panel_simple_shutdown(struct device *dev)
        panel_simple_disable(&panel->base);
 }
 
+static const struct drm_display_mode ampire_am800480r3tmqwa1h_mode = {
+       .clock = 33333,
+       .hdisplay = 800,
+       .hsync_start = 800 + 0,
+       .hsync_end = 800 + 0 + 255,
+       .htotal = 800 + 0 + 255 + 0,
+       .vdisplay = 480,
+       .vsync_start = 480 + 2,
+       .vsync_end = 480 + 2 + 45,
+       .vtotal = 480 + 2 + 45 + 0,
+       .vrefresh = 60,
+       .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
+};
+
+static const struct panel_desc ampire_am800480r3tmqwa1h = {
+       .modes = &ampire_am800480r3tmqwa1h_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 152,
+               .height = 91,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+};
+
 static const struct drm_display_mode auo_b101aw03_mode = {
        .clock = 51450,
        .hdisplay = 1024,
@@ -350,6 +417,29 @@ static const struct panel_desc auo_b101aw03 = {
        },
 };
 
+static const struct drm_display_mode auo_b101ean01_mode = {
+       .clock = 72500,
+       .hdisplay = 1280,
+       .hsync_start = 1280 + 119,
+       .hsync_end = 1280 + 119 + 32,
+       .htotal = 1280 + 119 + 32 + 21,
+       .vdisplay = 800,
+       .vsync_start = 800 + 4,
+       .vsync_end = 800 + 4 + 20,
+       .vtotal = 800 + 4 + 20 + 8,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc auo_b101ean01 = {
+       .modes = &auo_b101ean01_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 217,
+               .height = 136,
+       },
+};
+
 static const struct drm_display_mode auo_b101xtn01_mode = {
        .clock = 72000,
        .hdisplay = 1366,
@@ -615,24 +705,25 @@ static const struct panel_desc giantplus_gpg482739qs5 = {
                .width = 95,
                .height = 54,
        },
+       .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
 };
 
-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 display_timing hannstar_hsd070pww1_timing = {
+       .pixelclock = { 64300000, 71100000, 82000000 },
+       .hactive = { 1280, 1280, 1280 },
+       .hfront_porch = { 1, 1, 10 },
+       .hback_porch = { 1, 1, 10 },
+       .hsync_len = { 52, 158, 661 },
+       .vactive = { 800, 800, 800 },
+       .vfront_porch = { 1, 1, 10 },
+       .vback_porch = { 1, 1, 10 },
+       .vsync_len = { 1, 21, 203 },
+       .flags = DISPLAY_FLAGS_DE_HIGH,
 };
 
 static const struct panel_desc hannstar_hsd070pww1 = {
-       .modes = &hannstar_hsd070pww1_mode,
-       .num_modes = 1,
+       .timings = &hannstar_hsd070pww1_timing,
+       .num_timings = 1,
        .bpc = 6,
        .size = {
                .width = 151,
@@ -663,6 +754,31 @@ static const struct panel_desc hitachi_tx23d38vm0caa = {
        },
 };
 
+static const struct drm_display_mode innolux_at043tn24_mode = {
+       .clock = 9000,
+       .hdisplay = 480,
+       .hsync_start = 480 + 2,
+       .hsync_end = 480 + 2 + 41,
+       .htotal = 480 + 2 + 41 + 2,
+       .vdisplay = 272,
+       .vsync_start = 272 + 2,
+       .vsync_end = 272 + 2 + 11,
+       .vtotal = 272 + 2 + 11 + 2,
+       .vrefresh = 60,
+       .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+};
+
+static const struct panel_desc innolux_at043tn24 = {
+       .modes = &innolux_at043tn24_mode,
+       .num_modes = 1,
+       .bpc = 8,
+       .size = {
+               .width = 95,
+               .height = 54,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+};
+
 static const struct drm_display_mode innolux_g121i1_l01_mode = {
        .clock = 71000,
        .hdisplay = 1280,
@@ -733,6 +849,29 @@ static const struct panel_desc innolux_n156bge_l21 = {
        },
 };
 
+static const struct drm_display_mode innolux_zj070na_01p_mode = {
+       .clock = 51501,
+       .hdisplay = 1024,
+       .hsync_start = 1024 + 128,
+       .hsync_end = 1024 + 128 + 64,
+       .htotal = 1024 + 128 + 64 + 128,
+       .vdisplay = 600,
+       .vsync_start = 600 + 16,
+       .vsync_end = 600 + 16 + 4,
+       .vtotal = 600 + 16 + 4 + 16,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc innolux_zj070na_01p = {
+       .modes = &innolux_zj070na_01p_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 1024,
+               .height = 600,
+       },
+};
+
 static const struct drm_display_mode lg_lp129qe_mode = {
        .clock = 285250,
        .hdisplay = 2560,
@@ -756,6 +895,30 @@ static const struct panel_desc lg_lp129qe = {
        },
 };
 
+static const struct drm_display_mode ortustech_com43h4m85ulc_mode  = {
+       .clock = 25000,
+       .hdisplay = 480,
+       .hsync_start = 480 + 10,
+       .hsync_end = 480 + 10 + 10,
+       .htotal = 480 + 10 + 10 + 15,
+       .vdisplay = 800,
+       .vsync_start = 800 + 3,
+       .vsync_end = 800 + 3 + 3,
+       .vtotal = 800 + 3 + 3 + 3,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc ortustech_com43h4m85ulc = {
+       .modes = &ortustech_com43h4m85ulc_mode,
+       .num_modes = 1,
+       .bpc = 8,
+       .size = {
+               .width = 56,
+               .height = 93,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+};
+
 static const struct drm_display_mode samsung_ltn101nt05_mode = {
        .clock = 54030,
        .hdisplay = 1024,
@@ -779,10 +942,62 @@ static const struct panel_desc samsung_ltn101nt05 = {
        },
 };
 
+static const struct drm_display_mode samsung_ltn140at29_301_mode = {
+       .clock = 76300,
+       .hdisplay = 1366,
+       .hsync_start = 1366 + 64,
+       .hsync_end = 1366 + 64 + 48,
+       .htotal = 1366 + 64 + 48 + 128,
+       .vdisplay = 768,
+       .vsync_start = 768 + 2,
+       .vsync_end = 768 + 2 + 5,
+       .vtotal = 768 + 2 + 5 + 17,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc samsung_ltn140at29_301 = {
+       .modes = &samsung_ltn140at29_301_mode,
+       .num_modes = 1,
+       .bpc = 6,
+       .size = {
+               .width = 320,
+               .height = 187,
+       },
+};
+
+static const struct drm_display_mode shelly_sca07010_bfn_lnn_mode = {
+       .clock = 33300,
+       .hdisplay = 800,
+       .hsync_start = 800 + 1,
+       .hsync_end = 800 + 1 + 64,
+       .htotal = 800 + 1 + 64 + 64,
+       .vdisplay = 480,
+       .vsync_start = 480 + 1,
+       .vsync_end = 480 + 1 + 23,
+       .vtotal = 480 + 1 + 23 + 22,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc shelly_sca07010_bfn_lnn = {
+       .modes = &shelly_sca07010_bfn_lnn_mode,
+       .num_modes = 1,
+       .size = {
+               .width = 152,
+               .height = 91,
+       },
+       .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+};
+
 static const struct of_device_id platform_of_match[] = {
        {
+               .compatible = "ampire,am800480r3tmqwa1h",
+               .data = &ampire_am800480r3tmqwa1h,
+       }, {
                .compatible = "auo,b101aw03",
                .data = &auo_b101aw03,
+       }, {
+               .compatible = "auo,b101ean01",
+               .data = &auo_b101ean01,
        }, {
                .compatible = "auo,b101xtn01",
                .data = &auo_b101xtn01,
@@ -825,6 +1040,9 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "hit,tx23d38vm0caa",
                .data = &hitachi_tx23d38vm0caa
+       }, {
+               .compatible = "innolux,at043tn24",
+               .data = &innolux_at043tn24,
        }, {
                .compatible ="innolux,g121i1-l01",
                .data = &innolux_g121i1_l01
@@ -834,12 +1052,24 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "innolux,n156bge-l21",
                .data = &innolux_n156bge_l21,
+       }, {
+               .compatible = "innolux,zj070na-01p",
+               .data = &innolux_zj070na_01p,
        }, {
                .compatible = "lg,lp129qe",
                .data = &lg_lp129qe,
+       }, {
+               .compatible = "ortustech,com43h4m85ulc",
+               .data = &ortustech_com43h4m85ulc,
        }, {
                .compatible = "samsung,ltn101nt05",
                .data = &samsung_ltn101nt05,
+       }, {
+               .compatible = "samsung,ltn140at29-301",
+               .data = &samsung_ltn140at29_301,
+       }, {
+               .compatible = "shelly,sca07010-bfn-lnn",
+               .data = &shelly_sca07010_bfn_lnn,
        }, {
                /* sentinel */
        }
index 1d9b80c91a152585ba8c4380825e5964fe5e4cf0..e2d07085b6a55ab506d51935a25c6ea29ec32e5d 100644 (file)
@@ -102,7 +102,7 @@ static int qxl_drm_freeze(struct drm_device *dev)
 
        /* unpin the front buffers */
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+               const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
                if (crtc->enabled)
                        (*crtc_funcs->disable)(crtc);
        }
index 970f8e92dbb79bf5e954a8d917e7d4fbc46629cc..421ae130809b12576e6c526c686a4a2d825c029c 100644 (file)
@@ -1,3 +1,11 @@
+config DRM_RADEON_USERPTR
+       bool "Always enable userptr support"
+       depends on DRM_RADEON
+       select MMU_NOTIFIER
+       help
+         This option selects CONFIG_MMU_NOTIFIER if it isn't already
+         selected to enabled full userptr support.
+
 config DRM_RADEON_UMS
        bool "Enable userspace modesetting on radeon (DEPRECATED)"
        depends on DRM_RADEON
index 4605633e253b1b36a6cde19f4df2d9ff9db0b0c6..dea53e36a2ef3aa77fe5d0e68a2864db619b85c5 100644 (file)
@@ -81,7 +81,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.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_sync.o radeon_audio.o
+       radeon_sync.o radeon_audio.o radeon_dp_auxch.o radeon_dp_mst.o
 
 radeon-$(CONFIG_MMU_NOTIFIER) += radeon_mn.o
 
index 86807ee91bd13a7640f5b925aa4b5a4c0d9d615d..dac78ad24b31558aa53d917fb802865b6a122b61 100644 (file)
@@ -330,8 +330,10 @@ atombios_set_crtc_dtd_timing(struct drm_crtc *crtc,
                misc |= ATOM_COMPOSITESYNC;
        if (mode->flags & DRM_MODE_FLAG_INTERLACE)
                misc |= ATOM_INTERLACE;
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+       if (mode->flags & DRM_MODE_FLAG_DBLCLK)
                misc |= ATOM_DOUBLE_CLOCK_MODE;
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2;
 
        args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
        args.ucCRTC = radeon_crtc->crtc_id;
@@ -374,8 +376,10 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc,
                misc |= ATOM_COMPOSITESYNC;
        if (mode->flags & DRM_MODE_FLAG_INTERLACE)
                misc |= ATOM_INTERLACE;
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+       if (mode->flags & DRM_MODE_FLAG_DBLCLK)
                misc |= ATOM_DOUBLE_CLOCK_MODE;
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2;
 
        args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
        args.ucCRTC = radeon_crtc->crtc_id;
@@ -606,6 +610,13 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                }
        }
 
+       if (radeon_encoder->is_mst_encoder) {
+               struct radeon_encoder_mst *mst_enc = radeon_encoder->enc_priv;
+               struct radeon_connector_atom_dig *dig_connector = mst_enc->connector->con_priv;
+
+               dp_clock = dig_connector->dp_clock;
+       }
+
        /* use recommended ref_div for ss */
        if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
                if (radeon_crtc->ss_enabled) {
@@ -952,7 +963,9 @@ static bool atombios_crtc_prepare_pll(struct drm_crtc *crtc, struct drm_display_
        radeon_crtc->bpc = 8;
        radeon_crtc->ss_enabled = false;
 
-       if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
+       if (radeon_encoder->is_mst_encoder) {
+               radeon_dp_mst_prepare_pll(crtc, mode);
+       } else if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
            (radeon_encoder_get_dp_bridge_encoder_id(radeon_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) {
                struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
                struct drm_connector *connector =
@@ -2069,6 +2082,12 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
                radeon_crtc->connector = NULL;
                return false;
        }
+       if (radeon_crtc->encoder) {
+               struct radeon_encoder *radeon_encoder =
+                       to_radeon_encoder(radeon_crtc->encoder);
+
+               radeon_crtc->output_csc = radeon_encoder->output_csc;
+       }
        if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
                return false;
        if (!atombios_crtc_prepare_pll(crtc, adjusted_mode))
index 8d74de82456e880cb01d7e8132cf6c1caf5fa864..3e3290c203c625d781f7dfacc13977c50c54d34b 100644 (file)
@@ -158,7 +158,7 @@ done:
 #define HEADER_SIZE (BARE_ADDRESS_SIZE + 1)
 
 static ssize_t
-radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
+radeon_dp_aux_transfer_atom(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 {
        struct radeon_i2c_chan *chan =
                container_of(aux, struct radeon_i2c_chan, aux);
@@ -226,11 +226,20 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 
 void radeon_dp_aux_init(struct radeon_connector *radeon_connector)
 {
+       struct drm_device *dev = radeon_connector->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
        int ret;
 
        radeon_connector->ddc_bus->rec.hpd = radeon_connector->hpd.hpd;
        radeon_connector->ddc_bus->aux.dev = radeon_connector->base.kdev;
-       radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer;
+       if (ASIC_IS_DCE5(rdev)) {
+               if (radeon_auxch)
+                       radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer_native;
+               else
+                       radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer_atom;
+       } else {
+               radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer_atom;
+       }
 
        ret = drm_dp_aux_register(&radeon_connector->ddc_bus->aux);
        if (!ret)
@@ -301,8 +310,8 @@ static int dp_get_max_dp_pix_clock(int link_rate,
 
 /***** radeon specific DP functions *****/
 
-static int radeon_dp_get_max_link_rate(struct drm_connector *connector,
-                                      u8 dpcd[DP_DPCD_SIZE])
+int radeon_dp_get_max_link_rate(struct drm_connector *connector,
+                               u8 dpcd[DP_DPCD_SIZE])
 {
        int max_link_rate;
 
index c39c1d0d9d4e328d8df7f19caf2b52c68b1988b3..f57c1ab617bc877b4576e828ee203381626b177c 100644 (file)
@@ -671,7 +671,15 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        struct drm_connector *connector;
        struct radeon_connector *radeon_connector;
        struct radeon_connector_atom_dig *dig_connector;
+       struct radeon_encoder_atom_dig *dig_enc;
 
+       if (radeon_encoder_is_digital(encoder)) {
+               dig_enc = radeon_encoder->enc_priv;
+               if (dig_enc->active_mst_links)
+                       return ATOM_ENCODER_MODE_DP_MST;
+       }
+       if (radeon_encoder->is_mst_encoder || radeon_encoder->offset)
+               return ATOM_ENCODER_MODE_DP_MST;
        /* dp bridges are always DP */
        if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)
                return ATOM_ENCODER_MODE_DP;
@@ -823,7 +831,7 @@ union dig_encoder_control {
 };
 
 void
-atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode)
+atombios_dig_encoder_setup2(struct drm_encoder *encoder, int action, int panel_mode, int enc_override)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -920,7 +928,10 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
 
                        if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode) && (dp_clock == 270000))
                                args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
-                       args.v3.acConfig.ucDigSel = dig->dig_encoder;
+                       if (enc_override != -1)
+                               args.v3.acConfig.ucDigSel = enc_override;
+                       else
+                               args.v3.acConfig.ucDigSel = dig->dig_encoder;
                        args.v3.ucBitPerColor = radeon_atom_get_bpc(encoder);
                        break;
                case 4:
@@ -948,7 +959,11 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
                                else
                                        args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ;
                        }
-                       args.v4.acConfig.ucDigSel = dig->dig_encoder;
+
+                       if (enc_override != -1)
+                               args.v4.acConfig.ucDigSel = enc_override;
+                       else
+                               args.v4.acConfig.ucDigSel = dig->dig_encoder;
                        args.v4.ucBitPerColor = radeon_atom_get_bpc(encoder);
                        if (hpd_id == RADEON_HPD_NONE)
                                args.v4.ucHPD_ID = 0;
@@ -969,6 +984,12 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
 
 }
 
+void
+atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode)
+{
+       atombios_dig_encoder_setup2(encoder, action, panel_mode, -1);
+}
+
 union dig_transmitter_control {
        DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1;
        DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
@@ -978,7 +999,7 @@ union dig_transmitter_control {
 };
 
 void
-atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set)
+atombios_dig_transmitter_setup2(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set, int fe)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -1328,7 +1349,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
                                args.v5.asConfig.ucHPDSel = 0;
                        else
                                args.v5.asConfig.ucHPDSel = hpd_id + 1;
-                       args.v5.ucDigEncoderSel = 1 << dig_encoder;
+                       args.v5.ucDigEncoderSel = (fe != -1) ? (1 << fe) : (1 << dig_encoder);
                        args.v5.ucDPLaneSet = lane_set;
                        break;
                default:
@@ -1344,6 +1365,12 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
+void
+atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set)
+{
+       atombios_dig_transmitter_setup2(encoder, action, lane_num, lane_set, -1);
+}
+
 bool
 atombios_set_edp_panel_power(struct drm_connector *connector, int action)
 {
@@ -1687,6 +1714,11 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
        case DRM_MODE_DPMS_STANDBY:
        case DRM_MODE_DPMS_SUSPEND:
        case DRM_MODE_DPMS_OFF:
+
+               /* don't power off encoders with active MST links */
+               if (dig->active_mst_links)
+                       return;
+
                if (ASIC_IS_DCE4(rdev)) {
                        if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector)
                                atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
@@ -1955,6 +1987,53 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
        radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
 }
 
+void
+atombios_set_mst_encoder_crtc_source(struct drm_encoder *encoder, int fe)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+       int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
+       uint8_t frev, crev;
+       union crtc_source_param args;
+
+       memset(&args, 0, sizeof(args));
+
+       if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
+               return;
+
+       if (frev != 1 && crev != 2)
+               DRM_ERROR("Unknown table for MST %d, %d\n", frev, crev);
+
+       args.v2.ucCRTC = radeon_crtc->crtc_id;
+       args.v2.ucEncodeMode = ATOM_ENCODER_MODE_DP_MST;
+
+       switch (fe) {
+       case 0:
+               args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
+               break;
+       case 1:
+               args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
+               break;
+       case 2:
+               args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID;
+               break;
+       case 3:
+               args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID;
+               break;
+       case 4:
+               args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID;
+               break;
+       case 5:
+               args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID;
+               break;
+       case 6:
+               args.v2.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID;
+               break;
+       }
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
 static void
 atombios_apply_encoder_quirks(struct drm_encoder *encoder,
                              struct drm_display_mode *mode)
@@ -2003,7 +2082,14 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder,
        }
 }
 
-static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
+void radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx)
+{
+       if (enc_idx < 0)
+               return;
+       rdev->mode_info.active_encoders &= ~(1 << enc_idx);
+}
+
+int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -2012,71 +2098,79 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
        struct drm_encoder *test_encoder;
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
        uint32_t dig_enc_in_use = 0;
+       int enc_idx = -1;
 
+       if (fe_idx >= 0) {
+               enc_idx = fe_idx;
+               goto assigned;
+       }
        if (ASIC_IS_DCE6(rdev)) {
                /* DCE6 */
                switch (radeon_encoder->encoder_id) {
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
                        if (dig->linkb)
-                               return 1;
+                               enc_idx = 1;
                        else
-                               return 0;
+                               enc_idx = 0;
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
                        if (dig->linkb)
-                               return 3;
+                               enc_idx = 3;
                        else
-                               return 2;
+                               enc_idx = 2;
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
                        if (dig->linkb)
-                               return 5;
+                               enc_idx = 5;
                        else
-                               return 4;
+                               enc_idx = 4;
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
-                       return 6;
+                       enc_idx = 6;
                        break;
                }
+               goto assigned;
        } else if (ASIC_IS_DCE4(rdev)) {
                /* DCE4/5 */
                if (ASIC_IS_DCE41(rdev) && !ASIC_IS_DCE61(rdev)) {
                        /* ontario follows DCE4 */
                        if (rdev->family == CHIP_PALM) {
                                if (dig->linkb)
-                                       return 1;
+                                       enc_idx = 1;
                                else
-                                       return 0;
+                                       enc_idx = 0;
                        } else
                                /* llano follows DCE3.2 */
-                               return radeon_crtc->crtc_id;
+                               enc_idx = radeon_crtc->crtc_id;
                } else {
                        switch (radeon_encoder->encoder_id) {
                        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
                                if (dig->linkb)
-                                       return 1;
+                                       enc_idx = 1;
                                else
-                                       return 0;
+                                       enc_idx = 0;
                                break;
                        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
                                if (dig->linkb)
-                                       return 3;
+                                       enc_idx = 3;
                                else
-                                       return 2;
+                                       enc_idx = 2;
                                break;
                        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
                                if (dig->linkb)
-                                       return 5;
+                                       enc_idx = 5;
                                else
-                                       return 4;
+                                       enc_idx = 4;
                                break;
                        }
                }
+               goto assigned;
        }
 
        /* on DCE32 and encoder can driver any block so just crtc id */
        if (ASIC_IS_DCE32(rdev)) {
-               return radeon_crtc->crtc_id;
+               enc_idx = radeon_crtc->crtc_id;
+               goto assigned;
        }
 
        /* on DCE3 - LVTMA can only be driven by DIGB */
@@ -2104,6 +2198,17 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
        if (!(dig_enc_in_use & 1))
                return 0;
        return 1;
+
+assigned:
+       if (enc_idx == -1) {
+               DRM_ERROR("Got encoder index incorrect - returning 0\n");
+               return 0;
+       }
+       if (rdev->mode_info.active_encoders & (1 << enc_idx)) {
+               DRM_ERROR("chosen encoder in use %d\n", enc_idx);
+       }
+       rdev->mode_info.active_encoders |= (1 << enc_idx);
+       return enc_idx;
 }
 
 /* This only needs to be called once at startup */
@@ -2362,7 +2467,9 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
             ENCODER_OBJECT_ID_NONE)) {
                struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
                if (dig) {
-                       dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder);
+                       if (dig->dig_encoder >= 0)
+                               radeon_atom_release_dig_encoder(rdev, dig->dig_encoder);
+                       dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder, -1);
                        if (radeon_encoder->active_device & ATOM_DEVICE_DFP_SUPPORT) {
                                if (rdev->family >= CHIP_R600)
                                        dig->afmt = rdev->mode_info.afmt[dig->dig_encoder];
@@ -2464,10 +2571,18 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
 
 disable_done:
        if (radeon_encoder_is_digital(encoder)) {
-               dig = radeon_encoder->enc_priv;
-               dig->dig_encoder = -1;
-       }
-       radeon_encoder->active_device = 0;
+               if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
+                       if (rdev->asic->display.hdmi_enable)
+                               radeon_hdmi_enable(rdev, encoder, false);
+               }
+               if (atombios_get_encoder_mode(encoder) != ATOM_ENCODER_MODE_DP_MST) {
+                       dig = radeon_encoder->enc_priv;
+                       radeon_atom_release_dig_encoder(rdev, dig->dig_encoder);
+                       dig->dig_encoder = -1;
+                       radeon_encoder->active_device = 0;
+               }
+       } else
+               radeon_encoder->active_device = 0;
 }
 
 /* these are handled by the primary encoders */
index db08f17be76b47ea0d312e57ff292f5d83eba221..69556f5e247e7f1b78a19da8201c970a98fd462d 100644 (file)
@@ -2751,13 +2751,54 @@ void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                else /* current_index == 2 */
                        pl = &ps->high;
                seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
-               if (rdev->family >= CHIP_CEDAR) {
-                       seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u vddci: %u\n",
-                                  current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci);
-               } else {
-                       seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u\n",
-                                  current_index, pl->sclk, pl->mclk, pl->vddc);
-               }
+               seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u vddci: %u\n",
+                          current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+       }
+}
+
+u32 btc_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct rv7xx_ps *ps = rv770_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return pl->sclk;
+       }
+}
+
+u32 btc_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct rv7xx_ps *ps = rv770_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return pl->mclk;
        }
 }
 
index bcd2f1fe803fa9e35fc654625c496d98efe29f69..8730562323a8b77d0dd86ec399207806a6807ddc 100644 (file)
@@ -5922,6 +5922,20 @@ void ci_dpm_print_power_state(struct radeon_device *rdev,
        r600_dpm_print_ps_status(rdev, rps);
 }
 
+u32 ci_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       u32 sclk = ci_get_average_sclk_freq(rdev);
+
+       return sclk;
+}
+
+u32 ci_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       u32 mclk = ci_get_average_mclk_freq(rdev);
+
+       return mclk;
+}
+
 u32 ci_dpm_get_sclk(struct radeon_device *rdev, bool low)
 {
        struct ci_power_info *pi = ci_get_pi(rdev);
index 3e670d344a2047151e289ab7dce348001ddf4280..28faea9996f9e111d6b35e547587025aa93c3089 100644 (file)
@@ -141,6 +141,39 @@ static void cik_fini_cg(struct radeon_device *rdev);
 static void cik_enable_gui_idle_interrupt(struct radeon_device *rdev,
                                          bool enable);
 
+/**
+ * cik_get_allowed_info_register - fetch the register for the info ioctl
+ *
+ * @rdev: radeon_device pointer
+ * @reg: register offset in bytes
+ * @val: register value
+ *
+ * Returns 0 for success or -EINVAL for an invalid register
+ *
+ */
+int cik_get_allowed_info_register(struct radeon_device *rdev,
+                                 u32 reg, u32 *val)
+{
+       switch (reg) {
+       case GRBM_STATUS:
+       case GRBM_STATUS2:
+       case GRBM_STATUS_SE0:
+       case GRBM_STATUS_SE1:
+       case GRBM_STATUS_SE2:
+       case GRBM_STATUS_SE3:
+       case SRBM_STATUS:
+       case SRBM_STATUS2:
+       case (SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET):
+       case (SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET):
+       case UVD_STATUS:
+       /* TODO VCE */
+               *val = RREG32(reg);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 /* get temperature in millidegrees */
 int ci_get_temp(struct radeon_device *rdev)
 {
@@ -7394,12 +7427,12 @@ int cik_irq_set(struct radeon_device *rdev)
                (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
        cp_int_cntl |= PRIV_INSTR_INT_ENABLE | PRIV_REG_INT_ENABLE;
 
-       hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+       hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
 
        dma_cntl = RREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
        dma_cntl1 = RREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
@@ -7486,27 +7519,27 @@ int cik_irq_set(struct radeon_device *rdev)
        }
        if (rdev->irq.hpd[0]) {
                DRM_DEBUG("cik_irq_set: hpd 1\n");
-               hpd1 |= DC_HPDx_INT_EN;
+               hpd1 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[1]) {
                DRM_DEBUG("cik_irq_set: hpd 2\n");
-               hpd2 |= DC_HPDx_INT_EN;
+               hpd2 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[2]) {
                DRM_DEBUG("cik_irq_set: hpd 3\n");
-               hpd3 |= DC_HPDx_INT_EN;
+               hpd3 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[3]) {
                DRM_DEBUG("cik_irq_set: hpd 4\n");
-               hpd4 |= DC_HPDx_INT_EN;
+               hpd4 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[4]) {
                DRM_DEBUG("cik_irq_set: hpd 5\n");
-               hpd5 |= DC_HPDx_INT_EN;
+               hpd5 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[5]) {
                DRM_DEBUG("cik_irq_set: hpd 6\n");
-               hpd6 |= DC_HPDx_INT_EN;
+               hpd6 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
 
        WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
@@ -7678,6 +7711,36 @@ static inline void cik_irq_ack(struct radeon_device *rdev)
                tmp |= DC_HPDx_INT_ACK;
                WREG32(DC_HPD6_INT_CONTROL, tmp);
        }
+       if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD1_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD1_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD2_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD2_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD3_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD3_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD4_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD4_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD5_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD6_INT_CONTROL, tmp);
+       }
 }
 
 /**
@@ -7803,6 +7866,7 @@ int cik_irq_process(struct radeon_device *rdev)
        u8 me_id, pipe_id, queue_id;
        u32 ring_index;
        bool queue_hotplug = false;
+       bool queue_dp = false;
        bool queue_reset = false;
        u32 addr, status, mc_client;
        bool queue_thermal = false;
@@ -8048,6 +8112,48 @@ restart_ih:
                                        DRM_DEBUG("IH: HPD6\n");
                                }
                                break;
+                       case 6:
+                               if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 1\n");
+                               }
+                               break;
+                       case 7:
+                               if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 2\n");
+                               }
+                               break;
+                       case 8:
+                               if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 3\n");
+                               }
+                               break;
+                       case 9:
+                               if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 4\n");
+                               }
+                               break;
+                       case 10:
+                               if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 5\n");
+                               }
+                               break;
+                       case 11:
+                               if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 6\n");
+                               }
+                               break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
                                break;
@@ -8256,6 +8362,8 @@ restart_ih:
                rptr &= rdev->ih.ptr_mask;
                WREG32(IH_RB_RPTR, rptr);
        }
+       if (queue_dp)
+               schedule_work(&rdev->dp_work);
        if (queue_hotplug)
                schedule_work(&rdev->hotplug_work);
        if (queue_reset) {
index c648e1996dabac449dfb838e018cad85b2d3bb61..0089d837a8e39c4990cb0fa865a56e250dc2c859 100644 (file)
 #      define CLK_OD(x)                                ((x) << 6)
 #      define CLK_OD_MASK                              (0x1f << 6)
 
+#define UVD_STATUS                                     0xf6bc
+
 /* UVD clocks */
 
 #define CG_DCLK_CNTL                   0xC050009C
 #define VCE_UENC_REG_CLOCK_GATING      0x207c0
 #define VCE_SYS_INT_EN                 0x21300
 #      define VCE_SYS_INT_TRAP_INTERRUPT_EN    (1 << 3)
+#define VCE_LMI_VCPU_CACHE_40BIT_BAR   0x2145c
 #define VCE_LMI_CTRL2                  0x21474
 #define VCE_LMI_CTRL                   0x21498
 #define VCE_LMI_VM_CTRL                        0x214a0
index 973df064c14feb193a81c99109665c2186d03dc6..f848acfd3fc8a94fb4674cf13d9442857e367567 100644 (file)
@@ -1006,6 +1006,34 @@ static void evergreen_init_golden_registers(struct radeon_device *rdev)
        }
 }
 
+/**
+ * evergreen_get_allowed_info_register - fetch the register for the info ioctl
+ *
+ * @rdev: radeon_device pointer
+ * @reg: register offset in bytes
+ * @val: register value
+ *
+ * Returns 0 for success or -EINVAL for an invalid register
+ *
+ */
+int evergreen_get_allowed_info_register(struct radeon_device *rdev,
+                                       u32 reg, u32 *val)
+{
+       switch (reg) {
+       case GRBM_STATUS:
+       case GRBM_STATUS_SE0:
+       case GRBM_STATUS_SE1:
+       case SRBM_STATUS:
+       case SRBM_STATUS2:
+       case DMA_STATUS_REG:
+       case UVD_STATUS:
+               *val = RREG32(reg);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw,
                             unsigned *bankh, unsigned *mtaspect,
                             unsigned *tile_split)
@@ -4392,12 +4420,12 @@ int evergreen_irq_set(struct radeon_device *rdev)
                return 0;
        }
 
-       hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
-       hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+       hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+       hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
        if (rdev->family == CHIP_ARUBA)
                thermal_int = RREG32(TN_CG_THERMAL_INT_CTRL) &
                        ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
@@ -4486,27 +4514,27 @@ int evergreen_irq_set(struct radeon_device *rdev)
        }
        if (rdev->irq.hpd[0]) {
                DRM_DEBUG("evergreen_irq_set: hpd 1\n");
-               hpd1 |= DC_HPDx_INT_EN;
+               hpd1 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[1]) {
                DRM_DEBUG("evergreen_irq_set: hpd 2\n");
-               hpd2 |= DC_HPDx_INT_EN;
+               hpd2 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[2]) {
                DRM_DEBUG("evergreen_irq_set: hpd 3\n");
-               hpd3 |= DC_HPDx_INT_EN;
+               hpd3 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[3]) {
                DRM_DEBUG("evergreen_irq_set: hpd 4\n");
-               hpd4 |= DC_HPDx_INT_EN;
+               hpd4 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[4]) {
                DRM_DEBUG("evergreen_irq_set: hpd 5\n");
-               hpd5 |= DC_HPDx_INT_EN;
+               hpd5 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[5]) {
                DRM_DEBUG("evergreen_irq_set: hpd 6\n");
-               hpd6 |= DC_HPDx_INT_EN;
+               hpd6 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.afmt[0]) {
                DRM_DEBUG("evergreen_irq_set: hdmi 0\n");
@@ -4700,6 +4728,38 @@ static void evergreen_irq_ack(struct radeon_device *rdev)
                tmp |= DC_HPDx_INT_ACK;
                WREG32(DC_HPD6_INT_CONTROL, tmp);
        }
+
+       if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD1_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD1_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD2_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD2_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD3_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD3_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD4_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD4_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD5_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD6_INT_CONTROL, tmp);
+       }
+
        if (rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG) {
                tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET);
                tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
@@ -4780,6 +4840,7 @@ int evergreen_irq_process(struct radeon_device *rdev)
        u32 ring_index;
        bool queue_hotplug = false;
        bool queue_hdmi = false;
+       bool queue_dp = false;
        bool queue_thermal = false;
        u32 status, addr;
 
@@ -5019,6 +5080,48 @@ restart_ih:
                                        DRM_DEBUG("IH: HPD6\n");
                                }
                                break;
+                       case 6:
+                               if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 1\n");
+                               }
+                               break;
+                       case 7:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 2\n");
+                               }
+                               break;
+                       case 8:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 3\n");
+                               }
+                               break;
+                       case 9:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 4\n");
+                               }
+                               break;
+                       case 10:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 5\n");
+                               }
+                               break;
+                       case 11:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 6\n");
+                               }
+                               break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
                                break;
@@ -5151,6 +5254,8 @@ restart_ih:
                rptr &= rdev->ih.ptr_mask;
                WREG32(IH_RB_RPTR, rptr);
        }
+       if (queue_dp)
+               schedule_work(&rdev->dp_work);
        if (queue_hotplug)
                schedule_work(&rdev->hotplug_work);
        if (queue_hdmi)
index a8d1d5240fcb3088d1ea391ebcc8955c46f8c237..4aa5f755572b1593a8b6f7876cf5f7aed183715d 100644 (file)
 #define UVD_UDEC_DBW_ADDR_CONFIG                       0xef54
 #define UVD_RBC_RB_RPTR                                        0xf690
 #define UVD_RBC_RB_WPTR                                        0xf694
+#define UVD_STATUS                                     0xf6bc
 
 /*
  * PM4
index 0e236d067d6648a5a5a17c5a60ead839372d0c0d..2d71da448487d40401e45e80fb4331f247e62249 100644 (file)
@@ -2820,6 +2820,29 @@ void kv_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
        }
 }
 
+u32 kv_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct kv_power_info *pi = kv_get_pi(rdev);
+       u32 current_index =
+               (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) >>
+               CURR_SCLK_INDEX_SHIFT;
+       u32 sclk;
+
+       if (current_index >= SMU__NUM_SCLK_DPM_STATE) {
+               return 0;
+       } else {
+               sclk = be32_to_cpu(pi->graphics_level[current_index].SclkFrequency);
+               return sclk;
+       }
+}
+
+u32 kv_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct kv_power_info *pi = kv_get_pi(rdev);
+
+       return pi->sys_info.bootup_uma_clk;
+}
+
 void kv_dpm_print_power_state(struct radeon_device *rdev,
                              struct radeon_ps *rps)
 {
index dab00812abaabeeeee6295041e730143c99fecba..e8a496ff007ee680d30a2bd688f30d094b58461c 100644 (file)
@@ -828,6 +828,35 @@ out:
        return err;
 }
 
+/**
+ * cayman_get_allowed_info_register - fetch the register for the info ioctl
+ *
+ * @rdev: radeon_device pointer
+ * @reg: register offset in bytes
+ * @val: register value
+ *
+ * Returns 0 for success or -EINVAL for an invalid register
+ *
+ */
+int cayman_get_allowed_info_register(struct radeon_device *rdev,
+                                    u32 reg, u32 *val)
+{
+       switch (reg) {
+       case GRBM_STATUS:
+       case GRBM_STATUS_SE0:
+       case GRBM_STATUS_SE1:
+       case SRBM_STATUS:
+       case SRBM_STATUS2:
+       case (DMA_STATUS_REG + DMA0_REGISTER_OFFSET):
+       case (DMA_STATUS_REG + DMA1_REGISTER_OFFSET):
+       case UVD_STATUS:
+               *val = RREG32(reg);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 int tn_get_temp(struct radeon_device *rdev)
 {
        u32 temp = RREG32_SMC(TN_CURRENT_GNB_TEMP) & 0x7ff;
index 7bc9f8d9804aa18db5bf63f6e93dc5557bcdce11..c3d531a1114b69b5b882d895c59eb698f6b4e5de 100644 (file)
@@ -4319,6 +4319,42 @@ void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
        }
 }
 
+u32 ni_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct ni_ps *ps = ni_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
+               CURRENT_STATE_INDEX_SHIFT;
+
+       if (current_index >= ps->performance_level_count) {
+               return 0;
+       } else {
+               pl = &ps->performance_levels[current_index];
+               return pl->sclk;
+       }
+}
+
+u32 ni_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct ni_ps *ps = ni_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
+               CURRENT_STATE_INDEX_SHIFT;
+
+       if (current_index >= ps->performance_level_count) {
+               return 0;
+       } else {
+               pl = &ps->performance_levels[current_index];
+               return pl->mclk;
+       }
+}
+
 u32 ni_dpm_get_sclk(struct radeon_device *rdev, bool low)
 {
        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
index 5db7b7d6feb0d2379d076ef8ae80d868a42ae74d..da310a70c0f01b880f8bac9bf7bb2abe6da5d7a1 100644 (file)
 #       define NI_REGAMMA_PROG_B                       4
 #       define NI_OVL_REGAMMA_MODE(x)                  (((x) & 0x7) << 4)
 
+#define NI_DP_MSE_LINK_TIMING                          0x73a0
+#      define NI_DP_MSE_LINK_FRAME                     (((x) & 0x3ff) << 0)
+#      define NI_DP_MSE_LINK_LINE                      (((x) & 0x3) << 16)
+
+#define NI_DP_MSE_MISC_CNTL                            0x736c
+#       define NI_DP_MSE_BLANK_CODE                    (((x) & 0x1) << 0)
+#       define NI_DP_MSE_TIMESTAMP_MODE                (((x) & 0x1) << 4)
+#       define NI_DP_MSE_ZERO_ENCODER                  (((x) & 0x1) << 8)
+
+#define NI_DP_MSE_RATE_CNTL                            0x7384
+#       define NI_DP_MSE_RATE_Y(x)                   (((x) & 0x3ffffff) << 0)
+#       define NI_DP_MSE_RATE_X(x)                   (((x) & 0x3f) << 26)
+
+#define NI_DP_MSE_RATE_UPDATE                          0x738c
+
+#define NI_DP_MSE_SAT0                                 0x7390
+#       define NI_DP_MSE_SAT_SRC0(x)                   (((x) & 0x7) << 0)
+#       define NI_DP_MSE_SAT_SLOT_COUNT0(x)            (((x) & 0x3f) << 8)
+#       define NI_DP_MSE_SAT_SRC1(x)                   (((x) & 0x7) << 16)
+#       define NI_DP_MSE_SAT_SLOT_COUNT1(x)            (((x) & 0x3f) << 24)
+
+#define NI_DP_MSE_SAT1                                 0x7394
+
+#define NI_DP_MSE_SAT2                                 0x7398
+
+#define NI_DP_MSE_SAT_UPDATE                           0x739c
+
+#define NI_DIG_BE_CNTL                                 0x7140
+#       define NI_DIG_FE_SOURCE_SELECT(x)              (((x) & 0x7f) << 8)
+#       define NI_DIG_FE_DIG_MODE(x)                   (((x) & 0x7) << 16)
+#       define NI_DIG_MODE_DP_SST                      0
+#       define NI_DIG_MODE_LVDS                        1
+#       define NI_DIG_MODE_TMDS_DVI                    2
+#       define NI_DIG_MODE_TMDS_HDMI                   3
+#       define NI_DIG_MODE_DP_MST                      5
+#       define NI_DIG_HPD_SELECT(x)                    (((x) & 0x7) << 28)
+
+#define NI_DIG_FE_CNTL                                 0x7000
+#       define NI_DIG_SOURCE_SELECT(x)                 (((x) & 0x3) << 0)
+#       define NI_DIG_STEREOSYNC_SELECT(x)             (((x) & 0x3) << 4)
+#       define NI_DIG_STEREOSYNC_GATE_EN(x)            (((x) & 0x1) << 8)
+#       define NI_DIG_DUAL_LINK_ENABLE(x)              (((x) & 0x1) << 16)
+#       define NI_DIG_SWAP(x)                          (((x) & 0x1) << 18)
+#       define NI_DIG_SYMCLK_FE_ON                     (0x1 << 24)
 #endif
index 6b44580440d09a10053abcb53bf6f6c048d4e063..3b290838918cfc3d04910616c25fd20df810fa89 100644 (file)
 #define MC_PMG_CMD_MRS2                                 0x2b5c
 #define MC_SEQ_PMG_CMD_MRS2_LP                          0x2b60
 
+#define AUX_CONTROL                                    0x6200
+#define        AUX_EN                                  (1 << 0)
+#define        AUX_LS_READ_EN                          (1 << 8)
+#define        AUX_LS_UPDATE_DISABLE(x)                (((x) & 0x1) << 12)
+#define        AUX_HPD_DISCON(x)                       (((x) & 0x1) << 16)
+#define        AUX_DET_EN                              (1 << 18)
+#define        AUX_HPD_SEL(x)                          (((x) & 0x7) << 20)
+#define        AUX_IMPCAL_REQ_EN                       (1 << 24)
+#define        AUX_TEST_MODE                           (1 << 28)
+#define        AUX_DEGLITCH_EN                         (1 << 29)
+#define AUX_SW_CONTROL                                 0x6204
+#define        AUX_SW_GO                               (1 << 0)
+#define        AUX_LS_READ_TRIG                        (1 << 2)
+#define        AUX_SW_START_DELAY(x)                   (((x) & 0xf) << 4)
+#define        AUX_SW_WR_BYTES(x)                      (((x) & 0x1f) << 16)
+
+#define AUX_SW_INTERRUPT_CONTROL                       0x620c
+#define        AUX_SW_DONE_INT                         (1 << 0)
+#define        AUX_SW_DONE_ACK                         (1 << 1)
+#define        AUX_SW_DONE_MASK                        (1 << 2)
+#define        AUX_SW_LS_DONE_INT                      (1 << 4)
+#define        AUX_SW_LS_DONE_MASK                     (1 << 6)
+#define AUX_SW_STATUS                                  0x6210
+#define        AUX_SW_DONE                             (1 << 0)
+#define        AUX_SW_REQ                              (1 << 1)
+#define        AUX_SW_RX_TIMEOUT_STATE(x)              (((x) & 0x7) << 4)
+#define        AUX_SW_RX_TIMEOUT                       (1 << 7)
+#define        AUX_SW_RX_OVERFLOW                      (1 << 8)
+#define        AUX_SW_RX_HPD_DISCON                    (1 << 9)
+#define        AUX_SW_RX_PARTIAL_BYTE                  (1 << 10)
+#define        AUX_SW_NON_AUX_MODE                     (1 << 11)
+#define        AUX_SW_RX_MIN_COUNT_VIOL                (1 << 12)
+#define        AUX_SW_RX_INVALID_STOP                  (1 << 14)
+#define        AUX_SW_RX_SYNC_INVALID_L                (1 << 17)
+#define        AUX_SW_RX_SYNC_INVALID_H                (1 << 18)
+#define        AUX_SW_RX_INVALID_START                 (1 << 19)
+#define        AUX_SW_RX_RECV_NO_DET                   (1 << 20)
+#define        AUX_SW_RX_RECV_INVALID_H                (1 << 22)
+#define        AUX_SW_RX_RECV_INVALID_V                (1 << 23)
+
+#define AUX_SW_DATA                                    0x6218
+#define AUX_SW_DATA_RW                                 (1 << 0)
+#define AUX_SW_DATA_MASK(x)                            (((x) & 0xff) << 8)
+#define AUX_SW_DATA_INDEX(x)                           (((x) & 0x1f) << 16)
+#define AUX_SW_AUTOINCREMENT_DISABLE                   (1 << 31)
+
 #define        LB_SYNC_RESET_SEL                               0x6b28
 #define                LB_SYNC_RESET_SEL_MASK                  (3 << 0)
 #define                LB_SYNC_RESET_SEL_SHIFT                 0
 #define UVD_UDEC_DBW_ADDR_CONFIG                       0xEF54
 #define UVD_RBC_RB_RPTR                                        0xF690
 #define UVD_RBC_RB_WPTR                                        0xF694
+#define UVD_STATUS                                     0xf6bc
 
 /*
  * PM4
index 2fcad344492f526a98b46b34d2979cd9dd5a872e..8f6d862a188228101dc9070f5ab2ada5f819d1a6 100644 (file)
@@ -108,6 +108,32 @@ static void r600_pcie_gen2_enable(struct radeon_device *rdev);
 extern int evergreen_rlc_resume(struct radeon_device *rdev);
 extern void rv770_set_clk_bypass_mode(struct radeon_device *rdev);
 
+/**
+ * r600_get_allowed_info_register - fetch the register for the info ioctl
+ *
+ * @rdev: radeon_device pointer
+ * @reg: register offset in bytes
+ * @val: register value
+ *
+ * Returns 0 for success or -EINVAL for an invalid register
+ *
+ */
+int r600_get_allowed_info_register(struct radeon_device *rdev,
+                                  u32 reg, u32 *val)
+{
+       switch (reg) {
+       case GRBM_STATUS:
+       case GRBM_STATUS2:
+       case R_000E50_SRBM_STATUS:
+       case DMA_STATUS_REG:
+       case UVD_STATUS:
+               *val = RREG32(reg);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 /**
  * r600_get_xclk - get the xclk
  *
index 5587603b4a891c1f2cfcf7873dd8aa9e173907df..d2abe481954fc14a8146c0f9db0f0a6e73816900 100644 (file)
@@ -111,6 +111,8 @@ extern int radeon_deep_color;
 extern int radeon_use_pflipirq;
 extern int radeon_bapm;
 extern int radeon_backlight;
+extern int radeon_auxch;
+extern int radeon_mst;
 
 /*
  * Copy from radeon_drv.h so we don't have to include both and have conflicting
@@ -505,7 +507,7 @@ struct radeon_bo {
        pid_t                           pid;
 
        struct radeon_mn                *mn;
-       struct interval_tree_node       mn_it;
+       struct list_head                mn_list;
 };
 #define gem_to_radeon_bo(gobj) container_of((gobj), struct radeon_bo, gem_base)
 
@@ -1565,6 +1567,7 @@ struct radeon_dpm {
        int                     new_active_crtc_count;
        u32                     current_active_crtcs;
        int                     current_active_crtc_count;
+       bool single_display;
        struct radeon_dpm_dynamic_state dyn_state;
        struct radeon_dpm_fan fan;
        u32 tdp_limit;
@@ -1856,6 +1859,8 @@ struct radeon_asic {
        u32 (*get_xclk)(struct radeon_device *rdev);
        /* get the gpu clock counter */
        uint64_t (*get_gpu_clock_counter)(struct radeon_device *rdev);
+       /* get register for info ioctl */
+       int (*get_allowed_info_register)(struct radeon_device *rdev, u32 reg, u32 *val);
        /* gart */
        struct {
                void (*tlb_flush)(struct radeon_device *rdev);
@@ -1984,6 +1989,8 @@ struct radeon_asic {
                u32 (*fan_ctrl_get_mode)(struct radeon_device *rdev);
                int (*set_fan_speed_percent)(struct radeon_device *rdev, u32 speed);
                int (*get_fan_speed_percent)(struct radeon_device *rdev, u32 *speed);
+               u32 (*get_current_sclk)(struct radeon_device *rdev);
+               u32 (*get_current_mclk)(struct radeon_device *rdev);
        } dpm;
        /* pageflipping */
        struct {
@@ -2407,6 +2414,7 @@ struct radeon_device {
        struct radeon_rlc rlc;
        struct radeon_mec mec;
        struct work_struct hotplug_work;
+       struct work_struct dp_work;
        struct work_struct audio_work;
        int num_crtc; /* number of crtcs */
        struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
@@ -2931,6 +2939,7 @@ static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v)
 #define radeon_mc_wait_for_idle(rdev) (rdev)->asic->mc_wait_for_idle((rdev))
 #define radeon_get_xclk(rdev) (rdev)->asic->get_xclk((rdev))
 #define radeon_get_gpu_clock_counter(rdev) (rdev)->asic->get_gpu_clock_counter((rdev))
+#define radeon_get_allowed_info_register(rdev, r, v) (rdev)->asic->get_allowed_info_register((rdev), (r), (v))
 #define radeon_dpm_init(rdev) rdev->asic->dpm.init((rdev))
 #define radeon_dpm_setup_asic(rdev) rdev->asic->dpm.setup_asic((rdev))
 #define radeon_dpm_enable(rdev) rdev->asic->dpm.enable((rdev))
@@ -2949,6 +2958,8 @@ static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v)
 #define radeon_dpm_vblank_too_short(rdev) rdev->asic->dpm.vblank_too_short((rdev))
 #define radeon_dpm_powergate_uvd(rdev, g) rdev->asic->dpm.powergate_uvd((rdev), (g))
 #define radeon_dpm_enable_bapm(rdev, e) rdev->asic->dpm.enable_bapm((rdev), (e))
+#define radeon_dpm_get_current_sclk(rdev) rdev->asic->dpm.get_current_sclk((rdev))
+#define radeon_dpm_get_current_mclk(rdev) rdev->asic->dpm.get_current_mclk((rdev))
 
 /* Common functions */
 /* AGP */
index c0ecd128b14bf584964b0787637740ff76ba845c..fafd8ce4d58fc6a844b9615aa3b013cf793123c6 100644 (file)
@@ -136,6 +136,11 @@ static void radeon_register_accessor_init(struct radeon_device *rdev)
        }
 }
 
+static int radeon_invalid_get_allowed_info_register(struct radeon_device *rdev,
+                                                   u32 reg, u32 *val)
+{
+       return -EINVAL;
+}
 
 /* helper to disable agp */
 /**
@@ -199,6 +204,7 @@ static struct radeon_asic r100_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r100_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r100_pci_gart_tlb_flush,
                .get_page_entry = &r100_pci_gart_get_page_entry,
@@ -266,6 +272,7 @@ static struct radeon_asic r200_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r100_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r100_pci_gart_tlb_flush,
                .get_page_entry = &r100_pci_gart_get_page_entry,
@@ -361,6 +368,7 @@ static struct radeon_asic r300_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r300_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r100_pci_gart_tlb_flush,
                .get_page_entry = &r100_pci_gart_get_page_entry,
@@ -428,6 +436,7 @@ static struct radeon_asic r300_asic_pcie = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r300_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rv370_pcie_gart_tlb_flush,
                .get_page_entry = &rv370_pcie_gart_get_page_entry,
@@ -495,6 +504,7 @@ static struct radeon_asic r420_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r300_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rv370_pcie_gart_tlb_flush,
                .get_page_entry = &rv370_pcie_gart_get_page_entry,
@@ -562,6 +572,7 @@ static struct radeon_asic rs400_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &rs400_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rs400_gart_tlb_flush,
                .get_page_entry = &rs400_gart_get_page_entry,
@@ -629,6 +640,7 @@ static struct radeon_asic rs600_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &rs600_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rs600_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -696,6 +708,7 @@ static struct radeon_asic rs690_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &rs690_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rs400_gart_tlb_flush,
                .get_page_entry = &rs400_gart_get_page_entry,
@@ -763,6 +776,7 @@ static struct radeon_asic rv515_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &rv515_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rv370_pcie_gart_tlb_flush,
                .get_page_entry = &rv370_pcie_gart_get_page_entry,
@@ -830,6 +844,7 @@ static struct radeon_asic r520_asic = {
        .mmio_hdp_flush = NULL,
        .gui_idle = &r100_gui_idle,
        .mc_wait_for_idle = &r520_mc_wait_for_idle,
+       .get_allowed_info_register = radeon_invalid_get_allowed_info_register,
        .gart = {
                .tlb_flush = &rv370_pcie_gart_tlb_flush,
                .get_page_entry = &rv370_pcie_gart_get_page_entry,
@@ -925,6 +940,7 @@ static struct radeon_asic r600_asic = {
        .mc_wait_for_idle = &r600_mc_wait_for_idle,
        .get_xclk = &r600_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = r600_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r600_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1009,6 +1025,7 @@ static struct radeon_asic rv6xx_asic = {
        .mc_wait_for_idle = &r600_mc_wait_for_idle,
        .get_xclk = &r600_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = r600_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r600_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1080,6 +1097,8 @@ static struct radeon_asic rv6xx_asic = {
                .print_power_state = &rv6xx_dpm_print_power_state,
                .debugfs_print_current_performance_level = &rv6xx_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &rv6xx_dpm_force_performance_level,
+               .get_current_sclk = &rv6xx_dpm_get_current_sclk,
+               .get_current_mclk = &rv6xx_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &rs600_page_flip,
@@ -1099,6 +1118,7 @@ static struct radeon_asic rs780_asic = {
        .mc_wait_for_idle = &r600_mc_wait_for_idle,
        .get_xclk = &r600_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = r600_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r600_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1170,6 +1190,8 @@ static struct radeon_asic rs780_asic = {
                .print_power_state = &rs780_dpm_print_power_state,
                .debugfs_print_current_performance_level = &rs780_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &rs780_dpm_force_performance_level,
+               .get_current_sclk = &rs780_dpm_get_current_sclk,
+               .get_current_mclk = &rs780_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &rs600_page_flip,
@@ -1202,6 +1224,7 @@ static struct radeon_asic rv770_asic = {
        .mc_wait_for_idle = &r600_mc_wait_for_idle,
        .get_xclk = &rv770_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = r600_get_allowed_info_register,
        .gart = {
                .tlb_flush = &r600_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1274,6 +1297,8 @@ static struct radeon_asic rv770_asic = {
                .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &rv770_dpm_force_performance_level,
                .vblank_too_short = &rv770_dpm_vblank_too_short,
+               .get_current_sclk = &rv770_dpm_get_current_sclk,
+               .get_current_mclk = &rv770_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &rv770_page_flip,
@@ -1319,6 +1344,7 @@ static struct radeon_asic evergreen_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &rv770_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = evergreen_get_allowed_info_register,
        .gart = {
                .tlb_flush = &evergreen_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1391,6 +1417,8 @@ static struct radeon_asic evergreen_asic = {
                .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &rv770_dpm_force_performance_level,
                .vblank_too_short = &cypress_dpm_vblank_too_short,
+               .get_current_sclk = &rv770_dpm_get_current_sclk,
+               .get_current_mclk = &rv770_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -1410,6 +1438,7 @@ static struct radeon_asic sumo_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &r600_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = evergreen_get_allowed_info_register,
        .gart = {
                .tlb_flush = &evergreen_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1481,6 +1510,8 @@ static struct radeon_asic sumo_asic = {
                .print_power_state = &sumo_dpm_print_power_state,
                .debugfs_print_current_performance_level = &sumo_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &sumo_dpm_force_performance_level,
+               .get_current_sclk = &sumo_dpm_get_current_sclk,
+               .get_current_mclk = &sumo_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -1500,6 +1531,7 @@ static struct radeon_asic btc_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &rv770_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = evergreen_get_allowed_info_register,
        .gart = {
                .tlb_flush = &evergreen_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1572,6 +1604,8 @@ static struct radeon_asic btc_asic = {
                .debugfs_print_current_performance_level = &btc_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &rv770_dpm_force_performance_level,
                .vblank_too_short = &btc_dpm_vblank_too_short,
+               .get_current_sclk = &btc_dpm_get_current_sclk,
+               .get_current_mclk = &btc_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -1634,6 +1668,7 @@ static struct radeon_asic cayman_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &rv770_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = cayman_get_allowed_info_register,
        .gart = {
                .tlb_flush = &cayman_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1717,6 +1752,8 @@ static struct radeon_asic cayman_asic = {
                .debugfs_print_current_performance_level = &ni_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &ni_dpm_force_performance_level,
                .vblank_too_short = &ni_dpm_vblank_too_short,
+               .get_current_sclk = &ni_dpm_get_current_sclk,
+               .get_current_mclk = &ni_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -1736,6 +1773,7 @@ static struct radeon_asic trinity_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &r600_get_xclk,
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+       .get_allowed_info_register = cayman_get_allowed_info_register,
        .gart = {
                .tlb_flush = &cayman_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1819,6 +1857,8 @@ static struct radeon_asic trinity_asic = {
                .debugfs_print_current_performance_level = &trinity_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &trinity_dpm_force_performance_level,
                .enable_bapm = &trinity_dpm_enable_bapm,
+               .get_current_sclk = &trinity_dpm_get_current_sclk,
+               .get_current_mclk = &trinity_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -1868,6 +1908,7 @@ static struct radeon_asic si_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &si_get_xclk,
        .get_gpu_clock_counter = &si_get_gpu_clock_counter,
+       .get_allowed_info_register = si_get_allowed_info_register,
        .gart = {
                .tlb_flush = &si_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -1955,6 +1996,8 @@ static struct radeon_asic si_asic = {
                .fan_ctrl_get_mode = &si_fan_ctrl_get_mode,
                .get_fan_speed_percent = &si_fan_ctrl_get_fan_speed_percent,
                .set_fan_speed_percent = &si_fan_ctrl_set_fan_speed_percent,
+               .get_current_sclk = &si_dpm_get_current_sclk,
+               .get_current_mclk = &si_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -2032,6 +2075,7 @@ static struct radeon_asic ci_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &cik_get_xclk,
        .get_gpu_clock_counter = &cik_get_gpu_clock_counter,
+       .get_allowed_info_register = cik_get_allowed_info_register,
        .gart = {
                .tlb_flush = &cik_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -2123,6 +2167,8 @@ static struct radeon_asic ci_asic = {
                .fan_ctrl_get_mode = &ci_fan_ctrl_get_mode,
                .get_fan_speed_percent = &ci_fan_ctrl_get_fan_speed_percent,
                .set_fan_speed_percent = &ci_fan_ctrl_set_fan_speed_percent,
+               .get_current_sclk = &ci_dpm_get_current_sclk,
+               .get_current_mclk = &ci_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
@@ -2142,6 +2188,7 @@ static struct radeon_asic kv_asic = {
        .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
        .get_xclk = &cik_get_xclk,
        .get_gpu_clock_counter = &cik_get_gpu_clock_counter,
+       .get_allowed_info_register = cik_get_allowed_info_register,
        .gart = {
                .tlb_flush = &cik_pcie_gart_tlb_flush,
                .get_page_entry = &rs600_gart_get_page_entry,
@@ -2229,6 +2276,8 @@ static struct radeon_asic kv_asic = {
                .force_performance_level = &kv_dpm_force_performance_level,
                .powergate_uvd = &kv_dpm_powergate_uvd,
                .enable_bapm = &kv_dpm_enable_bapm,
+               .get_current_sclk = &kv_dpm_get_current_sclk,
+               .get_current_mclk = &kv_dpm_get_current_mclk,
        },
        .pflip = {
                .page_flip = &evergreen_page_flip,
index 72bdd3bf0d8e1208e6eace5d4c9cd2735f99e110..cf0a90bb61cab3a7bce074a931440a3d12cfa115 100644 (file)
@@ -384,6 +384,8 @@ u32 r600_gfx_get_wptr(struct radeon_device *rdev,
                      struct radeon_ring *ring);
 void r600_gfx_set_wptr(struct radeon_device *rdev,
                       struct radeon_ring *ring);
+int r600_get_allowed_info_register(struct radeon_device *rdev,
+                                  u32 reg, u32 *val);
 /* r600 irq */
 int r600_irq_process(struct radeon_device *rdev);
 int r600_irq_init(struct radeon_device *rdev);
@@ -433,6 +435,8 @@ void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
                                                       struct seq_file *m);
 int rv6xx_dpm_force_performance_level(struct radeon_device *rdev,
                                      enum radeon_dpm_forced_level level);
+u32 rv6xx_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 rv6xx_dpm_get_current_mclk(struct radeon_device *rdev);
 /* rs780 dpm */
 int rs780_dpm_init(struct radeon_device *rdev);
 int rs780_dpm_enable(struct radeon_device *rdev);
@@ -449,6 +453,8 @@ void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
                                                       struct seq_file *m);
 int rs780_dpm_force_performance_level(struct radeon_device *rdev,
                                      enum radeon_dpm_forced_level level);
+u32 rs780_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 rs780_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /*
  * rv770,rv730,rv710,rv740
@@ -488,6 +494,8 @@ void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
 int rv770_dpm_force_performance_level(struct radeon_device *rdev,
                                      enum radeon_dpm_forced_level level);
 bool rv770_dpm_vblank_too_short(struct radeon_device *rdev);
+u32 rv770_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 rv770_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /*
  * evergreen
@@ -540,6 +548,8 @@ struct radeon_fence *evergreen_copy_dma(struct radeon_device *rdev,
                                        unsigned num_gpu_pages,
                                        struct reservation_object *resv);
 int evergreen_get_temp(struct radeon_device *rdev);
+int evergreen_get_allowed_info_register(struct radeon_device *rdev,
+                                       u32 reg, u32 *val);
 int sumo_get_temp(struct radeon_device *rdev);
 int tn_get_temp(struct radeon_device *rdev);
 int cypress_dpm_init(struct radeon_device *rdev);
@@ -563,6 +573,8 @@ u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low);
 bool btc_dpm_vblank_too_short(struct radeon_device *rdev);
 void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                                                     struct seq_file *m);
+u32 btc_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 btc_dpm_get_current_mclk(struct radeon_device *rdev);
 int sumo_dpm_init(struct radeon_device *rdev);
 int sumo_dpm_enable(struct radeon_device *rdev);
 int sumo_dpm_late_enable(struct radeon_device *rdev);
@@ -581,6 +593,8 @@ void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev
                                                      struct seq_file *m);
 int sumo_dpm_force_performance_level(struct radeon_device *rdev,
                                     enum radeon_dpm_forced_level level);
+u32 sumo_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 sumo_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /*
  * cayman
@@ -637,6 +651,8 @@ uint32_t cayman_dma_get_wptr(struct radeon_device *rdev,
                             struct radeon_ring *ring);
 void cayman_dma_set_wptr(struct radeon_device *rdev,
                         struct radeon_ring *ring);
+int cayman_get_allowed_info_register(struct radeon_device *rdev,
+                                    u32 reg, u32 *val);
 
 int ni_dpm_init(struct radeon_device *rdev);
 void ni_dpm_setup_asic(struct radeon_device *rdev);
@@ -655,6 +671,8 @@ void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
 int ni_dpm_force_performance_level(struct radeon_device *rdev,
                                   enum radeon_dpm_forced_level level);
 bool ni_dpm_vblank_too_short(struct radeon_device *rdev);
+u32 ni_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 ni_dpm_get_current_mclk(struct radeon_device *rdev);
 int trinity_dpm_init(struct radeon_device *rdev);
 int trinity_dpm_enable(struct radeon_device *rdev);
 int trinity_dpm_late_enable(struct radeon_device *rdev);
@@ -674,6 +692,8 @@ void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *r
 int trinity_dpm_force_performance_level(struct radeon_device *rdev,
                                        enum radeon_dpm_forced_level level);
 void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable);
+u32 trinity_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 trinity_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /* DCE6 - SI */
 void dce6_bandwidth_update(struct radeon_device *rdev);
@@ -726,6 +746,8 @@ 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);
 int si_get_temp(struct radeon_device *rdev);
+int si_get_allowed_info_register(struct radeon_device *rdev,
+                                u32 reg, u32 *val);
 int si_dpm_init(struct radeon_device *rdev);
 void si_dpm_setup_asic(struct radeon_device *rdev);
 int si_dpm_enable(struct radeon_device *rdev);
@@ -746,6 +768,8 @@ int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
                                                 u32 speed);
 u32 si_fan_ctrl_get_mode(struct radeon_device *rdev);
 void si_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode);
+u32 si_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 si_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /* DCE8 - CIK */
 void dce8_bandwidth_update(struct radeon_device *rdev);
@@ -841,6 +865,8 @@ void cik_sdma_set_wptr(struct radeon_device *rdev,
                       struct radeon_ring *ring);
 int ci_get_temp(struct radeon_device *rdev);
 int kv_get_temp(struct radeon_device *rdev);
+int cik_get_allowed_info_register(struct radeon_device *rdev,
+                                 u32 reg, u32 *val);
 
 int ci_dpm_init(struct radeon_device *rdev);
 int ci_dpm_enable(struct radeon_device *rdev);
@@ -862,6 +888,8 @@ int ci_dpm_force_performance_level(struct radeon_device *rdev,
                                   enum radeon_dpm_forced_level level);
 bool ci_dpm_vblank_too_short(struct radeon_device *rdev);
 void ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate);
+u32 ci_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 ci_dpm_get_current_mclk(struct radeon_device *rdev);
 
 int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
                                                 u32 *speed);
@@ -890,6 +918,8 @@ int kv_dpm_force_performance_level(struct radeon_device *rdev,
                                   enum radeon_dpm_forced_level level);
 void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate);
 void kv_dpm_enable_bapm(struct radeon_device *rdev, bool enable);
+u32 kv_dpm_get_current_sclk(struct radeon_device *rdev);
+u32 kv_dpm_get_current_mclk(struct radeon_device *rdev);
 
 /* uvd v1.0 */
 uint32_t uvd_v1_0_get_rptr(struct radeon_device *rdev,
index fc1b3f34cf1827c7498512e7b9f4e36039787d41..8f285244c839a8c85ad186a1b877f94749776a58 100644 (file)
@@ -845,6 +845,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
 
        radeon_link_encoder_connector(dev);
 
+       radeon_setup_mst_connector(dev);
        return true;
 }
 
index b21ef69a34ac2a2703f7adad0ee20a15f07d3509..48d49e651a30cf94212fe2b4482178e7870ed029 100644 (file)
@@ -520,16 +520,40 @@ static int radeon_audio_set_avi_packet(struct drm_encoder *encoder,
        struct radeon_device *rdev = encoder->dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector = NULL;
        u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
        struct hdmi_avi_infoframe frame;
        int err;
 
+       list_for_each_entry(connector,
+               &encoder->dev->mode_config.connector_list, head) {
+               if (connector->encoder == encoder) {
+                       radeon_connector = to_radeon_connector(connector);
+                       break;
+               }
+       }
+
+       if (!radeon_connector) {
+               DRM_ERROR("Couldn't find encoder's connector\n");
+               return -ENOENT;
+       }
+
        err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
        if (err < 0) {
                DRM_ERROR("failed to setup AVI infoframe: %d\n", err);
                return err;
        }
 
+       if (drm_rgb_quant_range_selectable(radeon_connector_edid(connector))) {
+               if (radeon_encoder->output_csc == RADEON_OUTPUT_CSC_TVRGB)
+                       frame.quantization_range = HDMI_QUANTIZATION_RANGE_LIMITED;
+               else
+                       frame.quantization_range = HDMI_QUANTIZATION_RANGE_FULL;
+       } else {
+               frame.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
+       }
+
        err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
        if (err < 0) {
                DRM_ERROR("failed to pack AVI infoframe: %d\n", err);
index 63ccb8fa799c209bc82db257d3da0c8fc60ba052..d27e4ccb848c9c60e8a14f71336b790b125d2231 100644 (file)
@@ -76,7 +76,7 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev)
 
 static bool radeon_read_bios(struct radeon_device *rdev)
 {
-       uint8_t __iomem *bios;
+       uint8_t __iomem *bios, val1, val2;
        size_t size;
 
        rdev->bios = NULL;
@@ -86,15 +86,19 @@ static bool radeon_read_bios(struct radeon_device *rdev)
                return false;
        }
 
-       if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
+       val1 = readb(&bios[0]);
+       val2 = readb(&bios[1]);
+
+       if (size == 0 || val1 != 0x55 || val2 != 0xaa) {
                pci_unmap_rom(rdev->pdev, bios);
                return false;
        }
-       rdev->bios = kmemdup(bios, size, GFP_KERNEL);
+       rdev->bios = kzalloc(size, GFP_KERNEL);
        if (rdev->bios == NULL) {
                pci_unmap_rom(rdev->pdev, bios);
                return false;
        }
+       memcpy_fromio(rdev->bios, bios, size);
        pci_unmap_rom(rdev->pdev, bios);
        return true;
 }
index 27def67cb6beb31ca398956cf911ebdc0658755a..cebb65e07e1d13f0bee01ee753f4c8a76e0e22d5 100644 (file)
@@ -27,6 +27,7 @@
 #include <drm/drm_edid.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_dp_mst_helper.h>
 #include <drm/radeon_drm.h>
 #include "radeon.h"
 #include "radeon_audio.h"
 
 #include <linux/pm_runtime.h>
 
+static int radeon_dp_handle_hpd(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       int ret;
+
+       ret = radeon_dp_mst_check_status(radeon_connector);
+       if (ret == -EINVAL)
+               return 1;
+       return 0;
+}
 void radeon_connector_hotplug(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
 
+       if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
+               struct radeon_connector_atom_dig *dig_connector =
+                       radeon_connector->con_priv;
+
+               if (radeon_connector->is_mst_connector)
+                       return;
+               if (dig_connector->is_mst) {
+                       radeon_dp_handle_hpd(connector);
+                       return;
+               }
+       }
        /* bail if the connector does not have hpd pin, e.g.,
         * VGA, TV, etc.
         */
@@ -135,7 +157,7 @@ int radeon_get_monitor_bpc(struct drm_connector *connector)
                if (connector->display_info.bpc)
                        bpc = connector->display_info.bpc;
                else if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) {
-                       struct drm_connector_helper_funcs *connector_funcs =
+                       const struct drm_connector_helper_funcs *connector_funcs =
                                connector->helper_private;
                        struct drm_encoder *encoder = connector_funcs->best_encoder(connector);
                        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
@@ -225,7 +247,7 @@ radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_c
        struct radeon_device *rdev = dev->dev_private;
        struct drm_encoder *best_encoder = NULL;
        struct drm_encoder *encoder = NULL;
-       struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
+       const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
        bool connected;
        int i;
 
@@ -702,7 +724,7 @@ static int radeon_connector_set_property(struct drm_connector *connector, struct
                if (connector->encoder)
                        radeon_encoder = to_radeon_encoder(connector->encoder);
                else {
-                       struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
+                       const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
                        radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
                }
 
@@ -725,6 +747,30 @@ static int radeon_connector_set_property(struct drm_connector *connector, struct
                radeon_property_change_mode(&radeon_encoder->base);
        }
 
+       if (property == rdev->mode_info.output_csc_property) {
+               if (connector->encoder)
+                       radeon_encoder = to_radeon_encoder(connector->encoder);
+               else {
+                       const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
+                       radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
+               }
+
+               if (radeon_encoder->output_csc == val)
+                       return 0;
+
+               radeon_encoder->output_csc = val;
+
+               if (connector->encoder->crtc) {
+                       struct drm_crtc *crtc  = connector->encoder->crtc;
+                       const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+                       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+
+                       radeon_crtc->output_csc = radeon_encoder->output_csc;
+
+                       (*crtc_funcs->load_lut)(crtc);
+               }
+       }
+
        return 0;
 }
 
@@ -896,7 +942,7 @@ static int radeon_lvds_set_property(struct drm_connector *connector,
        if (connector->encoder)
                radeon_encoder = to_radeon_encoder(connector->encoder);
        else {
-               struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
+               const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
                radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
        }
 
@@ -964,7 +1010,7 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
        struct drm_encoder *encoder;
-       struct drm_encoder_helper_funcs *encoder_funcs;
+       const struct drm_encoder_helper_funcs *encoder_funcs;
        bool dret = false;
        enum drm_connector_status ret = connector_status_disconnected;
        int r;
@@ -1094,7 +1140,7 @@ static enum drm_connector_status
 radeon_tv_detect(struct drm_connector *connector, bool force)
 {
        struct drm_encoder *encoder;
-       struct drm_encoder_helper_funcs *encoder_funcs;
+       const struct drm_encoder_helper_funcs *encoder_funcs;
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
        enum drm_connector_status ret = connector_status_disconnected;
        int r;
@@ -1174,7 +1220,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
        struct drm_encoder *encoder = NULL;
-       struct drm_encoder_helper_funcs *encoder_funcs;
+       const struct drm_encoder_helper_funcs *encoder_funcs;
        int i, r;
        enum drm_connector_status ret = connector_status_disconnected;
        bool dret = false, broken_edid = false;
@@ -1585,6 +1631,9 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
        struct drm_encoder *encoder = radeon_best_single_encoder(connector);
        int r;
 
+       if (radeon_dig_connector->is_mst)
+               return connector_status_disconnected;
+
        r = pm_runtime_get_sync(connector->dev->dev);
        if (r < 0)
                return connector_status_disconnected;
@@ -1635,7 +1684,7 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
                        if (radeon_ddc_probe(radeon_connector, true)) /* try DDC */
                                ret = connector_status_connected;
                        else if (radeon_connector->dac_load_detect) { /* try load detection */
-                               struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
+                               const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
                                ret = encoder_funcs->detect(encoder, connector);
                        }
                }
@@ -1643,12 +1692,21 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
                radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
                if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
                        ret = connector_status_connected;
-                       if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
+                       if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
                                radeon_dp_getdpcd(radeon_connector);
+                               r = radeon_dp_mst_probe(radeon_connector);
+                               if (r == 1)
+                                       ret = connector_status_disconnected;
+                       }
                } else {
                        if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
-                               if (radeon_dp_getdpcd(radeon_connector))
-                                       ret = connector_status_connected;
+                               if (radeon_dp_getdpcd(radeon_connector)) {
+                                       r = radeon_dp_mst_probe(radeon_connector);
+                                       if (r == 1)
+                                               ret = connector_status_disconnected;
+                                       else
+                                               ret = connector_status_connected;
+                               }
                        } else {
                                /* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */
                                if (radeon_ddc_probe(radeon_connector, false))
@@ -1872,6 +1930,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                        drm_object_attach_property(&radeon_connector->base.base,
                                                   dev->mode_config.scaling_mode_property,
                                                   DRM_MODE_SCALE_NONE);
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        break;
                case DRM_MODE_CONNECTOR_DVII:
                case DRM_MODE_CONNECTOR_DVID:
@@ -1904,6 +1966,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           rdev->mode_info.audio_property,
                                                           RADEON_AUDIO_AUTO);
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
 
                        subpixel_order = SubPixelHorizontalRGB;
                        connector->interlace_allowed = true;
@@ -1950,6 +2016,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           dev->mode_config.scaling_mode_property,
                                                           DRM_MODE_SCALE_NONE);
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        /* no HPD on analog connectors */
                        radeon_connector->hpd.hpd = RADEON_HPD_NONE;
                        connector->polled = DRM_CONNECTOR_POLL_CONNECT;
@@ -1972,6 +2042,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           dev->mode_config.scaling_mode_property,
                                                           DRM_MODE_SCALE_NONE);
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        /* no HPD on analog connectors */
                        radeon_connector->hpd.hpd = RADEON_HPD_NONE;
                        connector->interlace_allowed = true;
@@ -2023,6 +2097,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                              rdev->mode_info.load_detect_property,
                                                              1);
                        }
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        connector->interlace_allowed = true;
                        if (connector_type == DRM_MODE_CONNECTOR_DVII)
                                connector->doublescan_allowed = true;
@@ -2068,6 +2146,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                           rdev->mode_info.audio_property,
                                                           RADEON_AUDIO_AUTO);
                        }
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        subpixel_order = SubPixelHorizontalRGB;
                        connector->interlace_allowed = true;
                        if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
@@ -2116,6 +2198,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                           rdev->mode_info.audio_property,
                                                           RADEON_AUDIO_AUTO);
                        }
+                       if (ASIC_IS_DCE5(rdev))
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                          rdev->mode_info.output_csc_property,
+                                                          RADEON_OUTPUT_CSC_BYPASS);
                        connector->interlace_allowed = true;
                        /* in theory with a DP to VGA converter... */
                        connector->doublescan_allowed = false;
@@ -2352,3 +2438,27 @@ radeon_add_legacy_connector(struct drm_device *dev,
        connector->display_info.subpixel_order = subpixel_order;
        drm_connector_register(connector);
 }
+
+void radeon_setup_mst_connector(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+
+       if (!ASIC_IS_DCE5(rdev))
+               return;
+
+       if (radeon_mst == 0)
+               return;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               int ret;
+
+               radeon_connector = to_radeon_connector(connector);
+
+               if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
+                       continue;
+
+               ret = radeon_dp_mst_init(radeon_connector);
+       }
+}
index bd7519fdd3f431cbce8c2bc6bd3e588e525be5cd..b7ca4c51462120fab3ab146dd74f653e8bcb91cb 100644 (file)
@@ -1442,6 +1442,11 @@ int radeon_device_init(struct radeon_device *rdev,
                DRM_ERROR("registering gem debugfs failed (%d).\n", r);
        }
 
+       r = radeon_mst_debugfs_init(rdev);
+       if (r) {
+               DRM_ERROR("registering mst debugfs failed (%d).\n", r);
+       }
+
        if (rdev->flags & RADEON_IS_AGP && !rdev->accel_working) {
                /* Acceleration not working on AGP card try again
                 * with fallback to PCI or PCIE GART
index 913fafa597ad210180c03e03618002a702cda441..d2e9e9efc159c053b954aed21840ebe7d91f2739 100644 (file)
@@ -154,7 +154,7 @@ static void dce5_crtc_load_lut(struct drm_crtc *crtc)
               (NI_GRPH_REGAMMA_MODE(NI_REGAMMA_BYPASS) |
                NI_OVL_REGAMMA_MODE(NI_REGAMMA_BYPASS)));
        WREG32(NI_OUTPUT_CSC_CONTROL + radeon_crtc->crtc_offset,
-              (NI_OUTPUT_CSC_GRPH_MODE(NI_OUTPUT_CSC_BYPASS) |
+              (NI_OUTPUT_CSC_GRPH_MODE(radeon_crtc->output_csc) |
                NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS)));
        /* XXX match this to the depth of the crtc fmt block, move to modeset? */
        WREG32(0x6940 + radeon_crtc->crtc_offset, 0);
@@ -1382,6 +1382,13 @@ static struct drm_prop_enum_list radeon_dither_enum_list[] =
        { RADEON_FMT_DITHER_ENABLE, "on" },
 };
 
+static struct drm_prop_enum_list radeon_output_csc_enum_list[] =
+{      { RADEON_OUTPUT_CSC_BYPASS, "bypass" },
+       { RADEON_OUTPUT_CSC_TVRGB, "tvrgb" },
+       { RADEON_OUTPUT_CSC_YCBCR601, "ycbcr601" },
+       { RADEON_OUTPUT_CSC_YCBCR709, "ycbcr709" },
+};
+
 static int radeon_modeset_create_props(struct radeon_device *rdev)
 {
        int sz;
@@ -1444,6 +1451,12 @@ static int radeon_modeset_create_props(struct radeon_device *rdev)
                                         "dither",
                                         radeon_dither_enum_list, sz);
 
+       sz = ARRAY_SIZE(radeon_output_csc_enum_list);
+       rdev->mode_info.output_csc_property =
+               drm_property_create_enum(rdev->ddev, 0,
+                                        "output_csc",
+                                        radeon_output_csc_enum_list, sz);
+
        return 0;
 }
 
diff --git a/drivers/gpu/drm/radeon/radeon_dp_auxch.c b/drivers/gpu/drm/radeon/radeon_dp_auxch.c
new file mode 100644 (file)
index 0000000..bf1fecc
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2015 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: Dave Airlie
+ */
+#include <drm/drmP.h>
+#include <drm/radeon_drm.h>
+#include "radeon.h"
+#include "nid.h"
+
+#define AUX_RX_ERROR_FLAGS (AUX_SW_RX_OVERFLOW |            \
+                           AUX_SW_RX_HPD_DISCON |           \
+                           AUX_SW_RX_PARTIAL_BYTE |         \
+                           AUX_SW_NON_AUX_MODE |            \
+                           AUX_SW_RX_MIN_COUNT_VIOL |       \
+                           AUX_SW_RX_INVALID_STOP |         \
+                           AUX_SW_RX_SYNC_INVALID_L |       \
+                           AUX_SW_RX_SYNC_INVALID_H |       \
+                           AUX_SW_RX_INVALID_START |        \
+                           AUX_SW_RX_RECV_NO_DET |          \
+                           AUX_SW_RX_RECV_INVALID_H |       \
+                           AUX_SW_RX_RECV_INVALID_V)
+
+#define AUX_SW_REPLY_GET_BYTE_COUNT(x) (((x) >> 24) & 0x1f)
+
+#define BARE_ADDRESS_SIZE 3
+
+static const u32 aux_offset[] =
+{
+       0x6200 - 0x6200,
+       0x6250 - 0x6200,
+       0x62a0 - 0x6200,
+       0x6300 - 0x6200,
+       0x6350 - 0x6200,
+       0x63a0 - 0x6200,
+};
+
+ssize_t
+radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
+{
+       struct radeon_i2c_chan *chan =
+               container_of(aux, struct radeon_i2c_chan, aux);
+       struct drm_device *dev = chan->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       int ret = 0, i;
+       uint32_t tmp, ack = 0;
+       int instance = chan->rec.i2c_id & 0xf;
+       u8 byte;
+       u8 *buf = msg->buffer;
+       int retry_count = 0;
+       int bytes;
+       int msize;
+       bool is_write = false;
+
+       if (WARN_ON(msg->size > 16))
+               return -E2BIG;
+
+       switch (msg->request & ~DP_AUX_I2C_MOT) {
+       case DP_AUX_NATIVE_WRITE:
+       case DP_AUX_I2C_WRITE:
+               is_write = true;
+               break;
+       case DP_AUX_NATIVE_READ:
+       case DP_AUX_I2C_READ:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* work out two sizes required */
+       msize = 0;
+       bytes = BARE_ADDRESS_SIZE;
+       if (msg->size) {
+               msize = msg->size - 1;
+               bytes++;
+               if (is_write)
+                       bytes += msg->size;
+       }
+
+       mutex_lock(&chan->mutex);
+
+       /* switch the pad to aux mode */
+       tmp = RREG32(chan->rec.mask_clk_reg);
+       tmp |= (1 << 16);
+       WREG32(chan->rec.mask_clk_reg, tmp);
+
+       /* setup AUX control register with correct HPD pin */
+       tmp = RREG32(AUX_CONTROL + aux_offset[instance]);
+
+       tmp &= AUX_HPD_SEL(0x7);
+       tmp |= AUX_HPD_SEL(chan->rec.hpd);
+       tmp |= AUX_EN | AUX_LS_READ_EN;
+
+       WREG32(AUX_CONTROL + aux_offset[instance], tmp);
+
+       /* atombios appears to write this twice lets copy it */
+       WREG32(AUX_SW_CONTROL + aux_offset[instance],
+              AUX_SW_WR_BYTES(bytes));
+       WREG32(AUX_SW_CONTROL + aux_offset[instance],
+              AUX_SW_WR_BYTES(bytes));
+
+       /* write the data header into the registers */
+       /* request, addres, msg size */
+       byte = (msg->request << 4);
+       WREG32(AUX_SW_DATA + aux_offset[instance],
+              AUX_SW_DATA_MASK(byte) | AUX_SW_AUTOINCREMENT_DISABLE);
+
+       byte = (msg->address >> 8) & 0xff;
+       WREG32(AUX_SW_DATA + aux_offset[instance],
+              AUX_SW_DATA_MASK(byte));
+
+       byte = msg->address & 0xff;
+       WREG32(AUX_SW_DATA + aux_offset[instance],
+              AUX_SW_DATA_MASK(byte));
+
+       byte = msize;
+       WREG32(AUX_SW_DATA + aux_offset[instance],
+              AUX_SW_DATA_MASK(byte));
+
+       /* if we are writing - write the msg buffer */
+       if (is_write) {
+               for (i = 0; i < msg->size; i++) {
+                       WREG32(AUX_SW_DATA + aux_offset[instance],
+                              AUX_SW_DATA_MASK(buf[i]));
+               }
+       }
+
+       /* clear the ACK */
+       WREG32(AUX_SW_INTERRUPT_CONTROL + aux_offset[instance], AUX_SW_DONE_ACK);
+
+       /* write the size and GO bits */
+       WREG32(AUX_SW_CONTROL + aux_offset[instance],
+              AUX_SW_WR_BYTES(bytes) | AUX_SW_GO);
+
+       /* poll the status registers - TODO irq support */
+       do {
+               tmp = RREG32(AUX_SW_STATUS + aux_offset[instance]);
+               if (tmp & AUX_SW_DONE) {
+                       break;
+               }
+               usleep_range(100, 200);
+       } while (retry_count++ < 1000);
+
+       if (retry_count >= 1000) {
+               DRM_ERROR("auxch hw never signalled completion, error %08x\n", tmp);
+               ret = -EIO;
+               goto done;
+       }
+
+       if (tmp & AUX_SW_RX_TIMEOUT) {
+               DRM_DEBUG_KMS("dp_aux_ch timed out\n");
+               ret = -ETIMEDOUT;
+               goto done;
+       }
+       if (tmp & AUX_RX_ERROR_FLAGS) {
+               DRM_DEBUG_KMS("dp_aux_ch flags not zero: %08x\n", tmp);
+               ret = -EIO;
+               goto done;
+       }
+
+       bytes = AUX_SW_REPLY_GET_BYTE_COUNT(tmp);
+       if (bytes) {
+               WREG32(AUX_SW_DATA + aux_offset[instance],
+                      AUX_SW_DATA_RW | AUX_SW_AUTOINCREMENT_DISABLE);
+
+               tmp = RREG32(AUX_SW_DATA + aux_offset[instance]);
+               ack = (tmp >> 8) & 0xff;
+
+               for (i = 0; i < bytes - 1; i++) {
+                       tmp = RREG32(AUX_SW_DATA + aux_offset[instance]);
+                       if (buf)
+                               buf[i] = (tmp >> 8) & 0xff;
+               }
+               if (buf)
+                       ret = bytes - 1;
+       }
+
+       WREG32(AUX_SW_INTERRUPT_CONTROL + aux_offset[instance], AUX_SW_DONE_ACK);
+
+       if (is_write)
+               ret = msg->size;
+done:
+       mutex_unlock(&chan->mutex);
+
+       if (ret >= 0)
+               msg->reply = ack >> 4;
+       return ret;
+}
diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c
new file mode 100644 (file)
index 0000000..1017338
--- /dev/null
@@ -0,0 +1,782 @@
+
+#include <drm/drmP.h>
+#include <drm/drm_dp_mst_helper.h>
+#include <drm/drm_fb_helper.h>
+
+#include "radeon.h"
+#include "atom.h"
+#include "ni_reg.h"
+
+static struct radeon_encoder *radeon_dp_create_fake_mst_encoder(struct radeon_connector *connector);
+
+static int radeon_atom_set_enc_offset(int id)
+{
+       static const int offsets[] = { EVERGREEN_CRTC0_REGISTER_OFFSET,
+                                      EVERGREEN_CRTC1_REGISTER_OFFSET,
+                                      EVERGREEN_CRTC2_REGISTER_OFFSET,
+                                      EVERGREEN_CRTC3_REGISTER_OFFSET,
+                                      EVERGREEN_CRTC4_REGISTER_OFFSET,
+                                      EVERGREEN_CRTC5_REGISTER_OFFSET,
+                                      0x13830 - 0x7030 };
+
+       return offsets[id];
+}
+
+static int radeon_dp_mst_set_be_cntl(struct radeon_encoder *primary,
+                                    struct radeon_encoder_mst *mst_enc,
+                                    enum radeon_hpd_id hpd, bool enable)
+{
+       struct drm_device *dev = primary->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t reg;
+       int retries = 0;
+       uint32_t temp;
+
+       reg = RREG32(NI_DIG_BE_CNTL + primary->offset);
+
+       /* set MST mode */
+       reg &= ~NI_DIG_FE_DIG_MODE(7);
+       reg |= NI_DIG_FE_DIG_MODE(NI_DIG_MODE_DP_MST);
+
+       if (enable)
+               reg |= NI_DIG_FE_SOURCE_SELECT(1 << mst_enc->fe);
+       else
+               reg &= ~NI_DIG_FE_SOURCE_SELECT(1 << mst_enc->fe);
+
+       reg |= NI_DIG_HPD_SELECT(hpd);
+       DRM_DEBUG_KMS("writing 0x%08x 0x%08x\n", NI_DIG_BE_CNTL + primary->offset, reg);
+       WREG32(NI_DIG_BE_CNTL + primary->offset, reg);
+
+       if (enable) {
+               uint32_t offset = radeon_atom_set_enc_offset(mst_enc->fe);
+
+               do {
+                       temp = RREG32(NI_DIG_FE_CNTL + offset);
+               } while ((temp & NI_DIG_SYMCLK_FE_ON) && retries++ < 10000);
+               if (retries == 10000)
+                       DRM_ERROR("timed out waiting for FE %d %d\n", primary->offset, mst_enc->fe);
+       }
+       return 0;
+}
+
+static int radeon_dp_mst_set_stream_attrib(struct radeon_encoder *primary,
+                                          int stream_number,
+                                          int fe,
+                                          int slots)
+{
+       struct drm_device *dev = primary->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       u32 temp, val;
+       int retries  = 0;
+       int satreg, satidx;
+
+       satreg = stream_number >> 1;
+       satidx = stream_number & 1;
+
+       temp = RREG32(NI_DP_MSE_SAT0 + satreg + primary->offset);
+
+       val = NI_DP_MSE_SAT_SLOT_COUNT0(slots) | NI_DP_MSE_SAT_SRC0(fe);
+
+       val <<= (16 * satidx);
+
+       temp &= ~(0xffff << (16 * satidx));
+
+       temp |= val;
+
+       DRM_DEBUG_KMS("writing 0x%08x 0x%08x\n", NI_DP_MSE_SAT0 + satreg + primary->offset, temp);
+       WREG32(NI_DP_MSE_SAT0 + satreg + primary->offset, temp);
+
+       WREG32(NI_DP_MSE_SAT_UPDATE + primary->offset, 1);
+
+       do {
+               temp = RREG32(NI_DP_MSE_SAT_UPDATE + primary->offset);
+       } while ((temp & 0x1) && retries++ < 10000);
+
+       if (retries == 10000)
+               DRM_ERROR("timed out waitin for SAT update %d\n", primary->offset);
+
+       /* MTP 16 ? */
+       return 0;
+}
+
+static int radeon_dp_mst_update_stream_attribs(struct radeon_connector *mst_conn,
+                                              struct radeon_encoder *primary)
+{
+       struct drm_device *dev = mst_conn->base.dev;
+       struct stream_attribs new_attribs[6];
+       int i;
+       int idx = 0;
+       struct radeon_connector *radeon_connector;
+       struct drm_connector *connector;
+
+       memset(new_attribs, 0, sizeof(new_attribs));
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               struct radeon_encoder *subenc;
+               struct radeon_encoder_mst *mst_enc;
+
+               radeon_connector = to_radeon_connector(connector);
+               if (!radeon_connector->is_mst_connector)
+                       continue;
+
+               if (radeon_connector->mst_port != mst_conn)
+                       continue;
+
+               subenc = radeon_connector->mst_encoder;
+               mst_enc = subenc->enc_priv;
+
+               if (!mst_enc->enc_active)
+                       continue;
+
+               new_attribs[idx].fe = mst_enc->fe;
+               new_attribs[idx].slots = drm_dp_mst_get_vcpi_slots(&mst_conn->mst_mgr, mst_enc->port);
+               idx++;
+       }
+
+       for (i = 0; i < idx; i++) {
+               if (new_attribs[i].fe != mst_conn->cur_stream_attribs[i].fe ||
+                   new_attribs[i].slots != mst_conn->cur_stream_attribs[i].slots) {
+                       radeon_dp_mst_set_stream_attrib(primary, i, new_attribs[i].fe, new_attribs[i].slots);
+                       mst_conn->cur_stream_attribs[i].fe = new_attribs[i].fe;
+                       mst_conn->cur_stream_attribs[i].slots = new_attribs[i].slots;
+               }
+       }
+
+       for (i = idx; i < mst_conn->enabled_attribs; i++) {
+               radeon_dp_mst_set_stream_attrib(primary, i, 0, 0);
+               mst_conn->cur_stream_attribs[i].fe = 0;
+               mst_conn->cur_stream_attribs[i].slots = 0;
+       }
+       mst_conn->enabled_attribs = idx;
+       return 0;
+}
+
+static int radeon_dp_mst_set_vcp_size(struct radeon_encoder *mst, uint32_t x, uint32_t y)
+{
+       struct drm_device *dev = mst->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder_mst *mst_enc = mst->enc_priv;
+       uint32_t val, temp;
+       uint32_t offset = radeon_atom_set_enc_offset(mst_enc->fe);
+       int retries = 0;
+
+       val = NI_DP_MSE_RATE_X(x) | NI_DP_MSE_RATE_Y(y);
+
+       WREG32(NI_DP_MSE_RATE_CNTL + offset, val);
+
+       do {
+               temp = RREG32(NI_DP_MSE_RATE_UPDATE + offset);
+       } while ((temp & 0x1) && (retries++ < 10000));
+
+       if (retries >= 10000)
+               DRM_ERROR("timed out wait for rate cntl %d\n", mst_enc->fe);
+       return 0;
+}
+
+static int radeon_dp_mst_get_ddc_modes(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct radeon_connector *master = radeon_connector->mst_port;
+       struct edid *edid;
+       int ret = 0;
+
+       edid = drm_dp_mst_get_edid(connector, &master->mst_mgr, radeon_connector->port);
+       radeon_connector->edid = edid;
+       DRM_DEBUG_KMS("edid retrieved %p\n", edid);
+       if (radeon_connector->edid) {
+               drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid);
+               ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid);
+               drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid);
+               return ret;
+       }
+       drm_mode_connector_update_edid_property(&radeon_connector->base, NULL);
+
+       return ret;
+}
+
+static int radeon_dp_mst_get_modes(struct drm_connector *connector)
+{
+       return radeon_dp_mst_get_ddc_modes(connector);
+}
+
+static enum drm_mode_status
+radeon_dp_mst_mode_valid(struct drm_connector *connector,
+                       struct drm_display_mode *mode)
+{
+       /* TODO - validate mode against available PBN for link */
+       if (mode->clock < 10000)
+               return MODE_CLOCK_LOW;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+               return MODE_H_ILLEGAL;
+
+       return MODE_OK;
+}
+
+struct drm_encoder *radeon_mst_best_encoder(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+
+       return &radeon_connector->mst_encoder->base;
+}
+
+static const struct drm_connector_helper_funcs radeon_dp_mst_connector_helper_funcs = {
+       .get_modes = radeon_dp_mst_get_modes,
+       .mode_valid = radeon_dp_mst_mode_valid,
+       .best_encoder = radeon_mst_best_encoder,
+};
+
+static enum drm_connector_status
+radeon_dp_mst_detect(struct drm_connector *connector, bool force)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct radeon_connector *master = radeon_connector->mst_port;
+
+       return drm_dp_mst_detect_port(connector, &master->mst_mgr, radeon_connector->port);
+}
+
+static void
+radeon_dp_mst_connector_destroy(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct radeon_encoder *radeon_encoder = radeon_connector->mst_encoder;
+
+       drm_encoder_cleanup(&radeon_encoder->base);
+       kfree(radeon_encoder);
+       drm_connector_cleanup(connector);
+       kfree(radeon_connector);
+}
+
+static void radeon_connector_dpms(struct drm_connector *connector, int mode)
+{
+       DRM_DEBUG_KMS("\n");
+}
+
+static const struct drm_connector_funcs radeon_dp_mst_connector_funcs = {
+       .dpms = radeon_connector_dpms,
+       .detect = radeon_dp_mst_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = radeon_dp_mst_connector_destroy,
+};
+
+static struct drm_connector *radeon_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
+                                                        struct drm_dp_mst_port *port,
+                                                        const char *pathprop)
+{
+       struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr);
+       struct drm_device *dev = master->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_connector *radeon_connector;
+       struct drm_connector *connector;
+
+       radeon_connector = kzalloc(sizeof(*radeon_connector), GFP_KERNEL);
+       if (!radeon_connector)
+               return NULL;
+
+       radeon_connector->is_mst_connector = true;
+       connector = &radeon_connector->base;
+       radeon_connector->port = port;
+       radeon_connector->mst_port = master;
+       DRM_DEBUG_KMS("\n");
+
+       drm_connector_init(dev, connector, &radeon_dp_mst_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort);
+       drm_connector_helper_add(connector, &radeon_dp_mst_connector_helper_funcs);
+       radeon_connector->mst_encoder = radeon_dp_create_fake_mst_encoder(master);
+
+       drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0);
+       drm_mode_connector_set_path_property(connector, pathprop);
+       drm_reinit_primary_mode_group(dev);
+
+       mutex_lock(&dev->mode_config.mutex);
+       radeon_fb_add_connector(rdev, connector);
+       mutex_unlock(&dev->mode_config.mutex);
+
+       drm_connector_register(connector);
+       return connector;
+}
+
+static void radeon_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
+                                           struct drm_connector *connector)
+{
+       struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr);
+       struct drm_device *dev = master->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+
+       drm_connector_unregister(connector);
+       /* need to nuke the connector */
+       mutex_lock(&dev->mode_config.mutex);
+       /* dpms off */
+       radeon_fb_remove_connector(rdev, connector);
+
+       drm_connector_cleanup(connector);
+       mutex_unlock(&dev->mode_config.mutex);
+       drm_reinit_primary_mode_group(dev);
+
+
+       kfree(connector);
+       DRM_DEBUG_KMS("\n");
+}
+
+static void radeon_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
+{
+       struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr);
+       struct drm_device *dev = master->base.dev;
+
+       drm_kms_helper_hotplug_event(dev);
+}
+
+struct drm_dp_mst_topology_cbs mst_cbs = {
+       .add_connector = radeon_dp_add_mst_connector,
+       .destroy_connector = radeon_dp_destroy_mst_connector,
+       .hotplug = radeon_dp_mst_hotplug,
+};
+
+struct radeon_connector *radeon_mst_find_connector(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_connector *connector;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+               if (!connector->encoder)
+                       continue;
+               if (!radeon_connector->is_mst_connector)
+                       continue;
+
+               DRM_DEBUG_KMS("checking %p vs %p\n", connector->encoder, encoder);
+               if (connector->encoder == encoder)
+                       return radeon_connector;
+       }
+       return NULL;
+}
+
+void radeon_dp_mst_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(radeon_crtc->encoder);
+       struct radeon_encoder_mst *mst_enc = radeon_encoder->enc_priv;
+       struct radeon_connector *radeon_connector = radeon_mst_find_connector(&radeon_encoder->base);
+       int dp_clock;
+       struct radeon_connector_atom_dig *dig_connector = mst_enc->connector->con_priv;
+
+       if (radeon_connector) {
+               radeon_connector->pixelclock_for_modeset = mode->clock;
+               if (radeon_connector->base.display_info.bpc)
+                       radeon_crtc->bpc = radeon_connector->base.display_info.bpc;
+               else
+                       radeon_crtc->bpc = 8;
+       }
+
+       DRM_DEBUG_KMS("dp_clock %p %d\n", dig_connector, dig_connector->dp_clock);
+       dp_clock = dig_connector->dp_clock;
+       radeon_crtc->ss_enabled =
+               radeon_atombios_get_asic_ss_info(rdev, &radeon_crtc->ss,
+                                                ASIC_INTERNAL_SS_ON_DP,
+                                                dp_clock);
+}
+
+static void
+radeon_mst_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder, *primary;
+       struct radeon_encoder_mst *mst_enc;
+       struct radeon_encoder_atom_dig *dig_enc;
+       struct radeon_connector *radeon_connector;
+       struct drm_crtc *crtc;
+       struct radeon_crtc *radeon_crtc;
+       int ret, slots;
+
+       if (!ASIC_IS_DCE5(rdev)) {
+               DRM_ERROR("got mst dpms on non-DCE5\n");
+               return;
+       }
+
+       radeon_connector = radeon_mst_find_connector(encoder);
+       if (!radeon_connector)
+               return;
+
+       radeon_encoder = to_radeon_encoder(encoder);
+
+       mst_enc = radeon_encoder->enc_priv;
+
+       primary = mst_enc->primary;
+
+       dig_enc = primary->enc_priv;
+
+       crtc = encoder->crtc;
+       DRM_DEBUG_KMS("got connector %d\n", dig_enc->active_mst_links);
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               dig_enc->active_mst_links++;
+
+               radeon_crtc = to_radeon_crtc(crtc);
+
+               if (dig_enc->active_mst_links == 1) {
+                       mst_enc->fe = dig_enc->dig_encoder;
+                       mst_enc->fe_from_be = true;
+                       atombios_set_mst_encoder_crtc_source(encoder, mst_enc->fe);
+
+                       atombios_dig_encoder_setup(&primary->base, ATOM_ENCODER_CMD_SETUP, 0);
+                       atombios_dig_transmitter_setup2(&primary->base, ATOM_TRANSMITTER_ACTION_ENABLE,
+                                                       0, 0, dig_enc->dig_encoder);
+
+                       if (radeon_dp_needs_link_train(mst_enc->connector) ||
+                           dig_enc->active_mst_links == 1) {
+                               radeon_dp_link_train(&primary->base, &mst_enc->connector->base);
+                       }
+
+               } else {
+                       mst_enc->fe = radeon_atom_pick_dig_encoder(encoder, radeon_crtc->crtc_id);
+                       if (mst_enc->fe == -1)
+                               DRM_ERROR("failed to get frontend for dig encoder\n");
+                       mst_enc->fe_from_be = false;
+                       atombios_set_mst_encoder_crtc_source(encoder, mst_enc->fe);
+               }
+
+               DRM_DEBUG_KMS("dig encoder is %d %d %d\n", dig_enc->dig_encoder,
+                             dig_enc->linkb, radeon_crtc->crtc_id);
+
+               ret = drm_dp_mst_allocate_vcpi(&radeon_connector->mst_port->mst_mgr,
+                                              radeon_connector->port,
+                                              mst_enc->pbn, &slots);
+               ret = drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr);
+
+               radeon_dp_mst_set_be_cntl(primary, mst_enc,
+                                         radeon_connector->mst_port->hpd.hpd, true);
+
+               mst_enc->enc_active = true;
+               radeon_dp_mst_update_stream_attribs(radeon_connector->mst_port, primary);
+               radeon_dp_mst_set_vcp_size(radeon_encoder, slots, 0);
+
+               atombios_dig_encoder_setup2(&primary->base, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0,
+                                           mst_enc->fe);
+               ret = drm_dp_check_act_status(&radeon_connector->mst_port->mst_mgr);
+
+               ret = drm_dp_update_payload_part2(&radeon_connector->mst_port->mst_mgr);
+
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               DRM_ERROR("DPMS OFF %d\n", dig_enc->active_mst_links);
+
+               if (!mst_enc->enc_active)
+                       return;
+
+               drm_dp_mst_reset_vcpi_slots(&radeon_connector->mst_port->mst_mgr, mst_enc->port);
+               ret = drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr);
+
+               drm_dp_check_act_status(&radeon_connector->mst_port->mst_mgr);
+               /* and this can also fail */
+               drm_dp_update_payload_part2(&radeon_connector->mst_port->mst_mgr);
+
+               drm_dp_mst_deallocate_vcpi(&radeon_connector->mst_port->mst_mgr, mst_enc->port);
+
+               mst_enc->enc_active = false;
+               radeon_dp_mst_update_stream_attribs(radeon_connector->mst_port, primary);
+
+               radeon_dp_mst_set_be_cntl(primary, mst_enc,
+                                         radeon_connector->mst_port->hpd.hpd, false);
+               atombios_dig_encoder_setup2(&primary->base, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0,
+                                           mst_enc->fe);
+
+               if (!mst_enc->fe_from_be)
+                       radeon_atom_release_dig_encoder(rdev, mst_enc->fe);
+
+               mst_enc->fe_from_be = false;
+               dig_enc->active_mst_links--;
+               if (dig_enc->active_mst_links == 0) {
+                       /* drop link */
+               }
+
+               break;
+       }
+
+}
+
+static bool radeon_mst_mode_fixup(struct drm_encoder *encoder,
+                                  const struct drm_display_mode *mode,
+                                  struct drm_display_mode *adjusted_mode)
+{
+       struct radeon_encoder_mst *mst_enc;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       int bpp = 24;
+
+       mst_enc = radeon_encoder->enc_priv;
+
+       mst_enc->pbn = drm_dp_calc_pbn_mode(adjusted_mode->clock, bpp);
+
+       mst_enc->primary->active_device = mst_enc->primary->devices & mst_enc->connector->devices;
+       DRM_DEBUG_KMS("setting active device to %08x from %08x %08x for encoder %d\n",
+                     mst_enc->primary->active_device, mst_enc->primary->devices,
+                     mst_enc->connector->devices, mst_enc->primary->base.encoder_type);
+
+
+       drm_mode_set_crtcinfo(adjusted_mode, 0);
+       {
+         struct radeon_connector_atom_dig *dig_connector;
+
+         dig_connector = mst_enc->connector->con_priv;
+         dig_connector->dp_lane_count = drm_dp_max_lane_count(dig_connector->dpcd);
+         dig_connector->dp_clock = radeon_dp_get_max_link_rate(&mst_enc->connector->base,
+                                                               dig_connector->dpcd);
+         DRM_DEBUG_KMS("dig clock %p %d %d\n", dig_connector,
+                       dig_connector->dp_lane_count, dig_connector->dp_clock);
+       }
+       return true;
+}
+
+static void radeon_mst_encoder_prepare(struct drm_encoder *encoder)
+{
+       struct radeon_connector *radeon_connector;
+       struct radeon_encoder *radeon_encoder, *primary;
+       struct radeon_encoder_mst *mst_enc;
+       struct radeon_encoder_atom_dig *dig_enc;
+
+       radeon_connector = radeon_mst_find_connector(encoder);
+       if (!radeon_connector) {
+               DRM_DEBUG_KMS("failed to find connector %p\n", encoder);
+               return;
+       }
+       radeon_encoder = to_radeon_encoder(encoder);
+
+       radeon_mst_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+
+       mst_enc = radeon_encoder->enc_priv;
+
+       primary = mst_enc->primary;
+
+       dig_enc = primary->enc_priv;
+
+       mst_enc->port = radeon_connector->port;
+
+       if (dig_enc->dig_encoder == -1) {
+               dig_enc->dig_encoder = radeon_atom_pick_dig_encoder(&primary->base, -1);
+               primary->offset = radeon_atom_set_enc_offset(dig_enc->dig_encoder);
+               atombios_set_mst_encoder_crtc_source(encoder, dig_enc->dig_encoder);
+
+
+       }
+       DRM_DEBUG_KMS("%d %d\n", dig_enc->dig_encoder, primary->offset);
+}
+
+static void
+radeon_mst_encoder_mode_set(struct drm_encoder *encoder,
+                            struct drm_display_mode *mode,
+                            struct drm_display_mode *adjusted_mode)
+{
+       DRM_DEBUG_KMS("\n");
+}
+
+static void radeon_mst_encoder_commit(struct drm_encoder *encoder)
+{
+       radeon_mst_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+       DRM_DEBUG_KMS("\n");
+}
+
+static const struct drm_encoder_helper_funcs radeon_mst_helper_funcs = {
+       .dpms = radeon_mst_encoder_dpms,
+       .mode_fixup = radeon_mst_mode_fixup,
+       .prepare = radeon_mst_encoder_prepare,
+       .mode_set = radeon_mst_encoder_mode_set,
+       .commit = radeon_mst_encoder_commit,
+};
+
+void radeon_dp_mst_encoder_destroy(struct drm_encoder *encoder)
+{
+       drm_encoder_cleanup(encoder);
+       kfree(encoder);
+}
+
+static const struct drm_encoder_funcs radeon_dp_mst_enc_funcs = {
+       .destroy = radeon_dp_mst_encoder_destroy,
+};
+
+static struct radeon_encoder *
+radeon_dp_create_fake_mst_encoder(struct radeon_connector *connector)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder;
+       struct radeon_encoder_mst *mst_enc;
+       struct drm_encoder *encoder;
+       const struct drm_connector_helper_funcs *connector_funcs = connector->base.helper_private;
+       struct drm_encoder *enc_master = connector_funcs->best_encoder(&connector->base);
+
+       DRM_DEBUG_KMS("enc master is %p\n", enc_master);
+       radeon_encoder = kzalloc(sizeof(*radeon_encoder), GFP_KERNEL);
+       if (!radeon_encoder)
+               return NULL;
+
+       radeon_encoder->enc_priv = kzalloc(sizeof(*mst_enc), GFP_KERNEL);
+       if (!radeon_encoder->enc_priv) {
+               kfree(radeon_encoder);
+               return NULL;
+       }
+       encoder = &radeon_encoder->base;
+       switch (rdev->num_crtc) {
+       case 1:
+               encoder->possible_crtcs = 0x1;
+               break;
+       case 2:
+       default:
+               encoder->possible_crtcs = 0x3;
+               break;
+       case 4:
+               encoder->possible_crtcs = 0xf;
+               break;
+       case 6:
+               encoder->possible_crtcs = 0x3f;
+               break;
+       }
+
+       drm_encoder_init(dev, &radeon_encoder->base, &radeon_dp_mst_enc_funcs,
+                        DRM_MODE_ENCODER_DPMST);
+       drm_encoder_helper_add(encoder, &radeon_mst_helper_funcs);
+
+       mst_enc = radeon_encoder->enc_priv;
+       mst_enc->connector = connector;
+       mst_enc->primary = to_radeon_encoder(enc_master);
+       radeon_encoder->is_mst_encoder = true;
+       return radeon_encoder;
+}
+
+int
+radeon_dp_mst_init(struct radeon_connector *radeon_connector)
+{
+       struct drm_device *dev = radeon_connector->base.dev;
+
+       if (!radeon_connector->ddc_bus->has_aux)
+               return 0;
+
+       radeon_connector->mst_mgr.cbs = &mst_cbs;
+       return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr, dev->dev,
+                                           &radeon_connector->ddc_bus->aux, 16, 6,
+                                           radeon_connector->base.base.id);
+}
+
+int
+radeon_dp_mst_probe(struct radeon_connector *radeon_connector)
+{
+       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+       int ret;
+       u8 msg[1];
+
+       if (dig_connector->dpcd[DP_DPCD_REV] < 0x12)
+               return 0;
+
+       ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_MSTM_CAP, msg,
+                              1);
+       if (ret) {
+               if (msg[0] & DP_MST_CAP) {
+                       DRM_DEBUG_KMS("Sink is MST capable\n");
+                       dig_connector->is_mst = true;
+               } else {
+                       DRM_DEBUG_KMS("Sink is not MST capable\n");
+                       dig_connector->is_mst = false;
+               }
+
+       }
+       drm_dp_mst_topology_mgr_set_mst(&radeon_connector->mst_mgr,
+                                       dig_connector->is_mst);
+       return dig_connector->is_mst;
+}
+
+int
+radeon_dp_mst_check_status(struct radeon_connector *radeon_connector)
+{
+       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+       int retry;
+
+       if (dig_connector->is_mst) {
+               u8 esi[16] = { 0 };
+               int dret;
+               int ret = 0;
+               bool handled;
+
+               dret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux,
+                                      DP_SINK_COUNT_ESI, esi, 8);
+go_again:
+               if (dret == 8) {
+                       DRM_DEBUG_KMS("got esi %02x %02x %02x\n", esi[0], esi[1], esi[2]);
+                       ret = drm_dp_mst_hpd_irq(&radeon_connector->mst_mgr, esi, &handled);
+
+                       if (handled) {
+                               for (retry = 0; retry < 3; retry++) {
+                                       int wret;
+                                       wret = drm_dp_dpcd_write(&radeon_connector->ddc_bus->aux,
+                                                                DP_SINK_COUNT_ESI + 1, &esi[1], 3);
+                                       if (wret == 3)
+                                               break;
+                               }
+
+                               dret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux,
+                                                       DP_SINK_COUNT_ESI, esi, 8);
+                               if (dret == 8) {
+                                       DRM_DEBUG_KMS("got esi2 %02x %02x %02x\n", esi[0], esi[1], esi[2]);
+                                       goto go_again;
+                               }
+                       } else
+                               ret = 0;
+
+                       return ret;
+               } else {
+                       DRM_DEBUG_KMS("failed to get ESI - device may have failed %d\n", ret);
+                       dig_connector->is_mst = false;
+                       drm_dp_mst_topology_mgr_set_mst(&radeon_connector->mst_mgr,
+                                                       dig_connector->is_mst);
+                       /* send a hotplug event */
+               }
+       }
+       return -EINVAL;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+
+static int radeon_debugfs_mst_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *)m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+       struct radeon_connector_atom_dig *dig_connector;
+       int i;
+
+       drm_modeset_lock_all(dev);
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
+                       continue;
+
+               radeon_connector = to_radeon_connector(connector);
+               dig_connector = radeon_connector->con_priv;
+               if (radeon_connector->is_mst_connector)
+                       continue;
+               if (!dig_connector->is_mst)
+                       continue;
+               drm_dp_mst_dump_topology(m, &radeon_connector->mst_mgr);
+
+               for (i = 0; i < radeon_connector->enabled_attribs; i++)
+                       seq_printf(m, "attrib %d: %d %d\n", i,
+                                  radeon_connector->cur_stream_attribs[i].fe,
+                                  radeon_connector->cur_stream_attribs[i].slots);
+       }
+       drm_modeset_unlock_all(dev);
+       return 0;
+}
+
+static struct drm_info_list radeon_debugfs_mst_list[] = {
+       {"radeon_mst_info", &radeon_debugfs_mst_info, 0, NULL},
+};
+#endif
+
+int radeon_mst_debugfs_init(struct radeon_device *rdev)
+{
+#if defined(CONFIG_DEBUG_FS)
+       return radeon_debugfs_add_files(rdev, radeon_debugfs_mst_list, 1);
+#endif
+       return 0;
+}
index 5d684beb48d32b9597fc604f6dee6790953fbf70..7d620d4b3f314d77407fbdbbf72c01435f1e4196 100644 (file)
  *   2.40.0 - Add RADEON_GEM_GTT_WC/UC, flush HDP cache before submitting
  *            CS to GPU on >= r600
  *   2.41.0 - evergreen/cayman: Add SET_BASE/DRAW_INDIRECT command parsing support
+ *   2.42.0 - Add VCE/VUI (Video Usability Information) support
  */
 #define KMS_DRIVER_MAJOR       2
-#define KMS_DRIVER_MINOR       41
+#define KMS_DRIVER_MINOR       42
 #define KMS_DRIVER_PATCHLEVEL  0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
@@ -190,6 +191,8 @@ int radeon_deep_color = 0;
 int radeon_use_pflipirq = 2;
 int radeon_bapm = -1;
 int radeon_backlight = -1;
+int radeon_auxch = -1;
+int radeon_mst = 0;
 
 MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
 module_param_named(no_wb, radeon_no_wb, int, 0444);
@@ -239,7 +242,7 @@ module_param_named(pcie_gen2, radeon_pcie_gen2, int, 0444);
 MODULE_PARM_DESC(msi, "MSI support (1 = enable, 0 = disable, -1 = auto)");
 module_param_named(msi, radeon_msi, int, 0444);
 
-MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (defaul 10000 = 10 seconds, 0 = disable)");
+MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (default 10000 = 10 seconds, 0 = disable)");
 module_param_named(lockup_timeout, radeon_lockup_timeout, int, 0444);
 
 MODULE_PARM_DESC(fastfb, "Direct FB access for IGP chips (0 = disable, 1 = enable)");
@@ -275,6 +278,12 @@ module_param_named(bapm, radeon_bapm, int, 0444);
 MODULE_PARM_DESC(backlight, "backlight support (1 = enable, 0 = disable, -1 = auto)");
 module_param_named(backlight, radeon_backlight, int, 0444);
 
+MODULE_PARM_DESC(auxch, "Use native auxch experimental support (1 = enable, 0 = disable, -1 = auto)");
+module_param_named(auxch, radeon_auxch, int, 0444);
+
+MODULE_PARM_DESC(mst, "DisplayPort MST experimental support (1 = enable, 0 = disable)");
+module_param_named(mst, radeon_mst, int, 0444);
+
 static struct pci_device_id pciidlist[] = {
        radeon_PCI_IDS
 };
index 3a297037cc176250fff7b1dae4a2566a8fd3c1ca..ef99917f000d96a7dcf3fc88f089bdf08e0afc28 100644 (file)
@@ -247,7 +247,16 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder)
 
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                radeon_connector = to_radeon_connector(connector);
-               if (radeon_encoder->active_device & radeon_connector->devices)
+               if (radeon_encoder->is_mst_encoder) {
+                       struct radeon_encoder_mst *mst_enc;
+
+                       if (!radeon_connector->is_mst_connector)
+                               continue;
+
+                       mst_enc = radeon_encoder->enc_priv;
+                       if (mst_enc->connector == radeon_connector->mst_port)
+                               return connector;
+               } else if (radeon_encoder->active_device & radeon_connector->devices)
                        return connector;
        }
        return NULL;
@@ -393,6 +402,9 @@ bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder,
        case DRM_MODE_CONNECTOR_DVID:
        case DRM_MODE_CONNECTOR_HDMIA:
        case DRM_MODE_CONNECTOR_DisplayPort:
+               if (radeon_connector->is_mst_connector)
+                       return false;
+
                dig_connector = radeon_connector->con_priv;
                if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
                    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
index ea276ff6d174283d0fee755530c90ea36c6d526d..aeb676708e60cfb1871326bfc5a689631bb98741 100644 (file)
@@ -257,6 +257,7 @@ static int radeonfb_create(struct drm_fb_helper *helper,
        }
 
        info->par = rfbdev;
+       info->skip_vt_switch = true;
 
        ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
        if (ret) {
@@ -434,3 +435,13 @@ bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
                return true;
        return false;
 }
+
+void radeon_fb_add_connector(struct radeon_device *rdev, struct drm_connector *connector)
+{
+       drm_fb_helper_add_one_connector(&rdev->mode_info.rfbdev->helper, connector);
+}
+
+void radeon_fb_remove_connector(struct radeon_device *rdev, struct drm_connector *connector)
+{
+       drm_fb_helper_remove_one_connector(&rdev->mode_info.rfbdev->helper, connector);
+}
index 00fc59762e0df3bba0758d1f18e90328e5726635..7162c935371c66a3abcf3fcf3734c1d234e3bb37 100644 (file)
@@ -87,6 +87,20 @@ static void radeon_hotplug_work_func(struct work_struct *work)
        drm_helper_hpd_irq_event(dev);
 }
 
+static void radeon_dp_work_func(struct work_struct *work)
+{
+       struct radeon_device *rdev = container_of(work, struct radeon_device,
+                                                 dp_work);
+       struct drm_device *dev = rdev->ddev;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_connector *connector;
+
+       /* this should take a mutex */
+       if (mode_config->num_connector) {
+               list_for_each_entry(connector, &mode_config->connector_list, head)
+                       radeon_connector_hotplug(connector);
+       }
+}
 /**
  * radeon_driver_irq_preinstall_kms - drm irq preinstall callback
  *
@@ -276,6 +290,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
        }
 
        INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
+       INIT_WORK(&rdev->dp_work, radeon_dp_work_func);
        INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
 
        rdev->irq.installed = true;
index 122eb5693ba191a7458a3496e6bb96b06aee1ac7..3db23007cdf469c8ee9271d23b25a4bbd078d2e6 100644 (file)
@@ -103,15 +103,14 @@ static const struct kgd2kfd_calls *kgd2kfd;
 bool radeon_kfd_init(void)
 {
 #if defined(CONFIG_HSA_AMD_MODULE)
-       bool (*kgd2kfd_init_p)(unsigned, const struct kfd2kgd_calls*,
-                               const struct kgd2kfd_calls**);
+       bool (*kgd2kfd_init_p)(unsigned, 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)) {
+       if (!kgd2kfd_init_p(KFD_INTERFACE_VERSION, &kgd2kfd)) {
                symbol_put(kgd2kfd_init);
                kgd2kfd = NULL;
 
@@ -120,7 +119,7 @@ bool radeon_kfd_init(void)
 
        return true;
 #elif defined(CONFIG_HSA_AMD)
-       if (!kgd2kfd_init(KFD_INTERFACE_VERSION, &kfd2kgd, &kgd2kfd)) {
+       if (!kgd2kfd_init(KFD_INTERFACE_VERSION, &kgd2kfd)) {
                kgd2kfd = NULL;
 
                return false;
@@ -143,7 +142,8 @@ void radeon_kfd_fini(void)
 void radeon_kfd_device_probe(struct radeon_device *rdev)
 {
        if (kgd2kfd)
-               rdev->kfd = kgd2kfd->probe((struct kgd_dev *)rdev, rdev->pdev);
+               rdev->kfd = kgd2kfd->probe((struct kgd_dev *)rdev,
+                       rdev->pdev, &kfd2kgd);
 }
 
 void radeon_kfd_device_init(struct radeon_device *rdev)
index 686411e4e4f6a3620289be34106ae5d38c9f6b93..7b2a7335cc5d557eafa6864d50cb6ebc9cdfb5ff 100644 (file)
@@ -547,6 +547,35 @@ static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                else
                        *value = 1;
                break;
+       case RADEON_INFO_CURRENT_GPU_TEMP:
+               /* get temperature in millidegrees C */
+               if (rdev->asic->pm.get_temperature)
+                       *value = radeon_get_temperature(rdev);
+               else
+                       *value = 0;
+               break;
+       case RADEON_INFO_CURRENT_GPU_SCLK:
+               /* get sclk in Mhz */
+               if (rdev->pm.dpm_enabled)
+                       *value = radeon_dpm_get_current_sclk(rdev) / 100;
+               else
+                       *value = rdev->pm.current_sclk / 100;
+               break;
+       case RADEON_INFO_CURRENT_GPU_MCLK:
+               /* get mclk in Mhz */
+               if (rdev->pm.dpm_enabled)
+                       *value = radeon_dpm_get_current_mclk(rdev) / 100;
+               else
+                       *value = rdev->pm.current_mclk / 100;
+               break;
+       case RADEON_INFO_READ_REG:
+               if (copy_from_user(value, value_ptr, sizeof(uint32_t))) {
+                       DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);
+                       return -EFAULT;
+               }
+               if (radeon_get_allowed_info_register(rdev, *value, value))
+                       return -EINVAL;
+               break;
        default:
                DRM_DEBUG_KMS("Invalid request %d\n", info->request);
                return -EINVAL;
index c89971d904c36696ad17e6ac4ac68f017a81b27c..45715307db7177a9af7393a697d255c8ed277344 100644 (file)
@@ -36,7 +36,7 @@
 static void radeon_legacy_encoder_disable(struct drm_encoder *encoder)
 {
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-       struct drm_encoder_helper_funcs *encoder_funcs;
+       const struct drm_encoder_helper_funcs *encoder_funcs;
 
        encoder_funcs = encoder->helper_private;
        encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
index a69bd441dd2d0cc612b9fa4d9e7711934270e3c5..01701376b23987c624a8d48a899e065d10d4bb8b 100644 (file)
@@ -53,6 +53,11 @@ struct radeon_mn {
        struct rb_root          objects;
 };
 
+struct radeon_mn_node {
+       struct interval_tree_node       it;
+       struct list_head                bos;
+};
+
 /**
  * radeon_mn_destroy - destroy the rmn
  *
@@ -64,14 +69,21 @@ static void radeon_mn_destroy(struct work_struct *work)
 {
        struct radeon_mn *rmn = container_of(work, struct radeon_mn, work);
        struct radeon_device *rdev = rmn->rdev;
-       struct radeon_bo *bo, *next;
+       struct radeon_mn_node *node, *next_node;
+       struct radeon_bo *bo, *next_bo;
 
        mutex_lock(&rdev->mn_lock);
        mutex_lock(&rmn->lock);
        hash_del(&rmn->node);
-       rbtree_postorder_for_each_entry_safe(bo, next, &rmn->objects, mn_it.rb) {
-               interval_tree_remove(&bo->mn_it, &rmn->objects);
-               bo->mn = NULL;
+       rbtree_postorder_for_each_entry_safe(node, next_node, &rmn->objects,
+                                            it.rb) {
+
+               interval_tree_remove(&node->it, &rmn->objects);
+               list_for_each_entry_safe(bo, next_bo, &node->bos, mn_list) {
+                       bo->mn = NULL;
+                       list_del_init(&bo->mn_list);
+               }
+               kfree(node);
        }
        mutex_unlock(&rmn->lock);
        mutex_unlock(&rdev->mn_lock);
@@ -121,32 +133,33 @@ static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn,
 
        it = interval_tree_iter_first(&rmn->objects, start, end);
        while (it) {
+               struct radeon_mn_node *node;
                struct radeon_bo *bo;
-               struct fence *fence;
                int r;
 
-               bo = container_of(it, struct radeon_bo, mn_it);
+               node = container_of(it, struct radeon_mn_node, it);
                it = interval_tree_iter_next(it, start, end);
 
-               r = radeon_bo_reserve(bo, true);
-               if (r) {
-                       DRM_ERROR("(%d) failed to reserve user bo\n", r);
-                       continue;
-               }
+               list_for_each_entry(bo, &node->bos, mn_list) {
 
-               fence = reservation_object_get_excl(bo->tbo.resv);
-               if (fence) {
-                       r = radeon_fence_wait((struct radeon_fence *)fence, false);
+                       r = radeon_bo_reserve(bo, true);
+                       if (r) {
+                               DRM_ERROR("(%d) failed to reserve user bo\n", r);
+                               continue;
+                       }
+
+                       r = reservation_object_wait_timeout_rcu(bo->tbo.resv,
+                               true, false, MAX_SCHEDULE_TIMEOUT);
                        if (r)
                                DRM_ERROR("(%d) failed to wait for user bo\n", r);
-               }
 
-               radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_CPU);
-               r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
-               if (r)
-                       DRM_ERROR("(%d) failed to validate user bo\n", r);
+                       radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_CPU);
+                       r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
+                       if (r)
+                               DRM_ERROR("(%d) failed to validate user bo\n", r);
 
-               radeon_bo_unreserve(bo);
+                       radeon_bo_unreserve(bo);
+               }
        }
        
        mutex_unlock(&rmn->lock);
@@ -223,24 +236,44 @@ int radeon_mn_register(struct radeon_bo *bo, unsigned long addr)
        unsigned long end = addr + radeon_bo_size(bo) - 1;
        struct radeon_device *rdev = bo->rdev;
        struct radeon_mn *rmn;
+       struct radeon_mn_node *node = NULL;
+       struct list_head bos;
        struct interval_tree_node *it;
 
        rmn = radeon_mn_get(rdev);
        if (IS_ERR(rmn))
                return PTR_ERR(rmn);
 
+       INIT_LIST_HEAD(&bos);
+
        mutex_lock(&rmn->lock);
 
-       it = interval_tree_iter_first(&rmn->objects, addr, end);
-       if (it) {
-               mutex_unlock(&rmn->lock);
-               return -EEXIST;
+       while ((it = interval_tree_iter_first(&rmn->objects, addr, end))) {
+               kfree(node);
+               node = container_of(it, struct radeon_mn_node, it);
+               interval_tree_remove(&node->it, &rmn->objects);
+               addr = min(it->start, addr);
+               end = max(it->last, end);
+               list_splice(&node->bos, &bos);
+       }
+
+       if (!node) {
+               node = kmalloc(sizeof(struct radeon_mn_node), GFP_KERNEL);
+               if (!node) {
+                       mutex_unlock(&rmn->lock);
+                       return -ENOMEM;
+               }
        }
 
        bo->mn = rmn;
-       bo->mn_it.start = addr;
-       bo->mn_it.last = end;
-       interval_tree_insert(&bo->mn_it, &rmn->objects);
+
+       node->it.start = addr;
+       node->it.last = end;
+       INIT_LIST_HEAD(&node->bos);
+       list_splice(&bos, &node->bos);
+       list_add(&bo->mn_list, &node->bos);
+
+       interval_tree_insert(&node->it, &rmn->objects);
 
        mutex_unlock(&rmn->lock);
 
@@ -258,6 +291,7 @@ void radeon_mn_unregister(struct radeon_bo *bo)
 {
        struct radeon_device *rdev = bo->rdev;
        struct radeon_mn *rmn;
+       struct list_head *head;
 
        mutex_lock(&rdev->mn_lock);
        rmn = bo->mn;
@@ -267,8 +301,19 @@ void radeon_mn_unregister(struct radeon_bo *bo)
        }
 
        mutex_lock(&rmn->lock);
-       interval_tree_remove(&bo->mn_it, &rmn->objects);
+       /* save the next list entry for later */
+       head = bo->mn_list.next;
+
        bo->mn = NULL;
+       list_del(&bo->mn_list);
+
+       if (list_empty(head)) {
+               struct radeon_mn_node *node;
+               node = container_of(head, struct radeon_mn_node, bos);
+               interval_tree_remove(&node->it, &rmn->objects);
+               kfree(node);
+       }
+
        mutex_unlock(&rmn->lock);
        mutex_unlock(&rdev->mn_lock);
 }
index 920a8be8abada71c8b1473f844e39ca3535807a8..fa91a17b81b69c715d162b8c92dd66a4a6add914 100644 (file)
@@ -33,6 +33,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_dp_helper.h>
+#include <drm/drm_dp_mst_helper.h>
 #include <drm/drm_fixed.h>
 #include <drm/drm_crtc_helper.h>
 #include <linux/i2c.h>
@@ -85,6 +86,13 @@ enum radeon_hpd_id {
        RADEON_HPD_NONE = 0xff,
 };
 
+enum radeon_output_csc {
+       RADEON_OUTPUT_CSC_BYPASS = 0,
+       RADEON_OUTPUT_CSC_TVRGB = 1,
+       RADEON_OUTPUT_CSC_YCBCR601 = 2,
+       RADEON_OUTPUT_CSC_YCBCR709 = 3,
+};
+
 #define RADEON_MAX_I2C_BUS 16
 
 /* radeon gpio-based i2c
@@ -255,6 +263,8 @@ struct radeon_mode_info {
        struct drm_property *audio_property;
        /* FMT dithering */
        struct drm_property *dither_property;
+       /* Output CSC */
+       struct drm_property *output_csc_property;
        /* hardcoded DFP edid from BIOS */
        struct edid *bios_hardcoded_edid;
        int bios_hardcoded_edid_size;
@@ -265,6 +275,9 @@ struct radeon_mode_info {
        u16 firmware_flags;
        /* pointer to backlight encoder */
        struct radeon_encoder *bl_encoder;
+
+       /* bitmask for active encoder frontends */
+       uint32_t active_encoders;
 };
 
 #define RADEON_MAX_BL_LEVEL 0xFF
@@ -357,6 +370,7 @@ struct radeon_crtc {
        u32 wm_low;
        u32 wm_high;
        struct drm_display_mode hw_mode;
+       enum radeon_output_csc output_csc;
 };
 
 struct radeon_encoder_primary_dac {
@@ -426,12 +440,24 @@ struct radeon_encoder_atom_dig {
        uint8_t backlight_level;
        int panel_mode;
        struct radeon_afmt *afmt;
+       int active_mst_links;
 };
 
 struct radeon_encoder_atom_dac {
        enum radeon_tv_std tv_std;
 };
 
+struct radeon_encoder_mst {
+       int crtc;
+       struct radeon_encoder *primary;
+       struct radeon_connector *connector;
+       struct drm_dp_mst_port *port;
+       int pbn;
+       int fe;
+       bool fe_from_be;
+       bool enc_active;
+};
+
 struct radeon_encoder {
        struct drm_encoder base;
        uint32_t encoder_enum;
@@ -450,6 +476,11 @@ struct radeon_encoder {
        bool is_ext_encoder;
        u16 caps;
        struct radeon_audio_funcs *audio;
+       enum radeon_output_csc output_csc;
+       bool can_mst;
+       uint32_t offset;
+       bool is_mst_encoder;
+       /* front end for this mst encoder */
 };
 
 struct radeon_connector_atom_dig {
@@ -460,6 +491,7 @@ struct radeon_connector_atom_dig {
        int dp_clock;
        int dp_lane_count;
        bool edp_on;
+       bool is_mst;
 };
 
 struct radeon_gpio_rec {
@@ -503,6 +535,11 @@ enum radeon_connector_dither {
        RADEON_FMT_DITHER_ENABLE = 1,
 };
 
+struct stream_attribs {
+       uint16_t fe;
+       uint16_t slots;
+};
+
 struct radeon_connector {
        struct drm_connector base;
        uint32_t connector_id;
@@ -524,6 +561,14 @@ struct radeon_connector {
        enum radeon_connector_audio audio;
        enum radeon_connector_dither dither;
        int pixelclock_for_modeset;
+       bool is_mst_connector;
+       struct radeon_connector *mst_port;
+       struct drm_dp_mst_port *port;
+       struct drm_dp_mst_topology_mgr mst_mgr;
+
+       struct radeon_encoder *mst_encoder;
+       struct stream_attribs cur_stream_attribs[6];
+       int enabled_attribs;
 };
 
 struct radeon_framebuffer {
@@ -708,15 +753,26 @@ extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
 extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
 extern int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
                                    struct drm_connector *connector);
+int radeon_dp_get_max_link_rate(struct drm_connector *connector,
+                               u8 *dpcd);
 extern void radeon_dp_set_rx_power_state(struct drm_connector *connector,
                                         u8 power_state);
 extern void radeon_dp_aux_init(struct radeon_connector *radeon_connector);
+extern ssize_t
+radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg);
+
 extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode);
+extern void atombios_dig_encoder_setup2(struct drm_encoder *encoder, int action, int panel_mode, int enc_override);
 extern void radeon_atom_encoder_init(struct radeon_device *rdev);
 extern void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev);
 extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder,
                                           int action, uint8_t lane_num,
                                           uint8_t lane_set);
+extern void atombios_dig_transmitter_setup2(struct drm_encoder *encoder,
+                                           int action, uint8_t lane_num,
+                                           uint8_t lane_set, int fe);
+extern void atombios_set_mst_encoder_crtc_source(struct drm_encoder *encoder,
+                                                int fe);
 extern void radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder);
 extern struct drm_encoder *radeon_get_external_encoder(struct drm_encoder *encoder);
 void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le);
@@ -929,7 +985,23 @@ bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
 void radeon_fb_output_poll_changed(struct radeon_device *rdev);
 
 void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id);
+
+void radeon_fb_add_connector(struct radeon_device *rdev, struct drm_connector *connector);
+void radeon_fb_remove_connector(struct radeon_device *rdev, struct drm_connector *connector);
+
 void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id);
 
 int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled);
+
+/* mst */
+int radeon_dp_mst_init(struct radeon_connector *radeon_connector);
+int radeon_dp_mst_probe(struct radeon_connector *radeon_connector);
+int radeon_dp_mst_check_status(struct radeon_connector *radeon_connector);
+int radeon_mst_debugfs_init(struct radeon_device *rdev);
+void radeon_dp_mst_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode);
+
+void radeon_setup_mst_connector(struct drm_device *dev);
+
+int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx);
+void radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx);
 #endif
index 33cf4108386dbba4ef70a0e372eb992d1ff7e4d3..c1ba83a8dd8c9333829aaa5f1384f65c7103d238 100644 (file)
@@ -837,12 +837,8 @@ static void radeon_dpm_thermal_work_handler(struct work_struct *work)
        radeon_pm_compute_clocks(rdev);
 }
 
-static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev,
-                                                    enum radeon_pm_state_type dpm_state)
+static bool radeon_dpm_single_display(struct radeon_device *rdev)
 {
-       int i;
-       struct radeon_ps *ps;
-       u32 ui_class;
        bool single_display = (rdev->pm.dpm.new_active_crtc_count < 2) ?
                true : false;
 
@@ -858,6 +854,17 @@ static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev,
        if (single_display && (r600_dpm_get_vrefresh(rdev) >= 120))
                single_display = false;
 
+       return single_display;
+}
+
+static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev,
+                                                    enum radeon_pm_state_type dpm_state)
+{
+       int i;
+       struct radeon_ps *ps;
+       u32 ui_class;
+       bool single_display = radeon_dpm_single_display(rdev);
+
        /* certain older asics have a separare 3D performance state,
         * so try that first if the user selected performance
         */
@@ -983,6 +990,7 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
        struct radeon_ps *ps;
        enum radeon_pm_state_type dpm_state;
        int ret;
+       bool single_display = radeon_dpm_single_display(rdev);
 
        /* if dpm init failed */
        if (!rdev->pm.dpm_enabled)
@@ -1007,6 +1015,9 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
                /* vce just modifies an existing state so force a change */
                if (ps->vce_active != rdev->pm.dpm.vce_active)
                        goto force;
+               /* user has made a display change (such as timing) */
+               if (rdev->pm.dpm.single_display != single_display)
+                       goto force;
                if ((rdev->family < CHIP_BARTS) || (rdev->flags & RADEON_IS_IGP)) {
                        /* for pre-BTC and APUs if the num crtcs changed but state is the same,
                         * all we need to do is update the display configuration.
@@ -1069,6 +1080,7 @@ force:
 
        rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
        rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
+       rdev->pm.dpm.single_display = single_display;
 
        /* wait for the rings to drain */
        for (i = 0; i < RADEON_NUM_RINGS; i++) {
index 2456f69efd2310233fac5c75a314a9060abe1a17..8c7872339c2a6f5e94bf601c47ed421e5caee352 100644 (file)
@@ -495,7 +495,7 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data)
        seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw);
        seq_printf(m, "%u dwords in ring\n", count);
 
-       if (!ring->ready)
+       if (!ring->ring)
                return 0;
 
        /* print 8 dw before current rptr as often it's the last executed
index d02aa1d0f5885408c877056bd4ac1ab0e1ed6f12..b292aca0f342d53856ec3eaf982b71fd8b0a7fa8 100644 (file)
@@ -598,6 +598,10 @@ static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
        enum dma_data_direction direction = write ?
                DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
 
+       /* double check that we don't free the table twice */
+       if (!ttm->sg->sgl)
+               return;
+
        /* free the sg table and pages again */
        dma_unmap_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents, direction);
 
index 976fe432f4e26fe83682d655ea983817cc19f05f..24f849f888bbdf93c6518a271105f8bb0d302368 100644 (file)
@@ -571,6 +571,7 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p)
                case 0x04000005: // rate control
                case 0x04000007: // motion estimation
                case 0x04000008: // rdo
+               case 0x04000009: // vui
                        break;
 
                case 0x03000001: // encode
index 9031f4b6982417462458b026f8c1503cde82397c..cb0afe78abed4562fe1df4e64769216f151285d8 100644 (file)
@@ -1001,6 +1001,28 @@ void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
                           ps->sclk_high, ps->max_voltage);
 }
 
+/* get the current sclk in 10 khz units */
+u32 rs780_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       u32 current_fb_div = RREG32(FVTHROT_STATUS_REG0) & CURRENT_FEEDBACK_DIV_MASK;
+       u32 func_cntl = RREG32(CG_SPLL_FUNC_CNTL);
+       u32 ref_div = ((func_cntl & SPLL_REF_DIV_MASK) >> SPLL_REF_DIV_SHIFT) + 1;
+       u32 post_div = ((func_cntl & SPLL_SW_HILEN_MASK) >> SPLL_SW_HILEN_SHIFT) + 1 +
+               ((func_cntl & SPLL_SW_LOLEN_MASK) >> SPLL_SW_LOLEN_SHIFT) + 1;
+       u32 sclk = (rdev->clock.spll.reference_freq * current_fb_div) /
+               (post_div * ref_div);
+
+       return sclk;
+}
+
+/* get the current mclk in 10 khz units */
+u32 rs780_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct igp_power_info *pi = rs780_get_pi(rdev);
+
+       return pi->bootup_uma_clk;
+}
+
 int rs780_dpm_force_performance_level(struct radeon_device *rdev,
                                      enum radeon_dpm_forced_level level)
 {
index 6a5c233361e9dbadbcb629c9583baf946e8abc7b..97e5a6f1ce5837fbaaba787991f83a0b4ab7f950 100644 (file)
@@ -2050,6 +2050,52 @@ void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
        }
 }
 
+/* get the current sclk in 10 khz units */
+u32 rv6xx_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct rv6xx_ps *ps = rv6xx_get_ps(rps);
+       struct rv6xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return pl->sclk;
+       }
+}
+
+/* get the current mclk in 10 khz units */
+u32 rv6xx_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct rv6xx_ps *ps = rv6xx_get_ps(rps);
+       struct rv6xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return pl->mclk;
+       }
+}
+
 void rv6xx_dpm_fini(struct radeon_device *rdev)
 {
        int i;
index 306732641b231aefb16ddc3186359ae872af5801..b9c770745a7a1f717cb9c894a6882c090fd8153c 100644 (file)
@@ -2492,6 +2492,50 @@ void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
        }
 }
 
+u32 rv770_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct rv7xx_ps *ps = rv770_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return  pl->sclk;
+       }
+}
+
+u32 rv770_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct rv7xx_ps *ps = rv770_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               return 0;
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               return  pl->mclk;
+       }
+}
+
 void rv770_dpm_fini(struct radeon_device *rdev)
 {
        int i;
index a7fb2735d4a929b7a20127bce4d7e3c759de2449..b1d74bc375d82f665dbb4455db5aa84db0c8d8dc 100644 (file)
@@ -1264,6 +1264,36 @@ static void si_init_golden_registers(struct radeon_device *rdev)
        }
 }
 
+/**
+ * si_get_allowed_info_register - fetch the register for the info ioctl
+ *
+ * @rdev: radeon_device pointer
+ * @reg: register offset in bytes
+ * @val: register value
+ *
+ * Returns 0 for success or -EINVAL for an invalid register
+ *
+ */
+int si_get_allowed_info_register(struct radeon_device *rdev,
+                                u32 reg, u32 *val)
+{
+       switch (reg) {
+       case GRBM_STATUS:
+       case GRBM_STATUS2:
+       case GRBM_STATUS_SE0:
+       case GRBM_STATUS_SE1:
+       case SRBM_STATUS:
+       case SRBM_STATUS2:
+       case (DMA_STATUS_REG + DMA0_REGISTER_OFFSET):
+       case (DMA_STATUS_REG + DMA1_REGISTER_OFFSET):
+       case UVD_STATUS:
+               *val = RREG32(reg);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 #define PCIE_BUS_CLK                10000
 #define TCLK                        (PCIE_BUS_CLK / 10)
 
@@ -6055,12 +6085,12 @@ int si_irq_set(struct radeon_device *rdev)
                (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
 
        if (!ASIC_IS_NODCE(rdev)) {
-               hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
-               hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
-               hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
-               hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
-               hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
-               hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+               hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+               hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+               hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+               hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+               hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
+               hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
        }
 
        dma_cntl = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
@@ -6123,27 +6153,27 @@ int si_irq_set(struct radeon_device *rdev)
        }
        if (rdev->irq.hpd[0]) {
                DRM_DEBUG("si_irq_set: hpd 1\n");
-               hpd1 |= DC_HPDx_INT_EN;
+               hpd1 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[1]) {
                DRM_DEBUG("si_irq_set: hpd 2\n");
-               hpd2 |= DC_HPDx_INT_EN;
+               hpd2 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[2]) {
                DRM_DEBUG("si_irq_set: hpd 3\n");
-               hpd3 |= DC_HPDx_INT_EN;
+               hpd3 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[3]) {
                DRM_DEBUG("si_irq_set: hpd 4\n");
-               hpd4 |= DC_HPDx_INT_EN;
+               hpd4 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[4]) {
                DRM_DEBUG("si_irq_set: hpd 5\n");
-               hpd5 |= DC_HPDx_INT_EN;
+               hpd5 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
        if (rdev->irq.hpd[5]) {
                DRM_DEBUG("si_irq_set: hpd 6\n");
-               hpd6 |= DC_HPDx_INT_EN;
+               hpd6 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
        }
 
        WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
@@ -6306,6 +6336,37 @@ static inline void si_irq_ack(struct radeon_device *rdev)
                tmp |= DC_HPDx_INT_ACK;
                WREG32(DC_HPD6_INT_CONTROL, tmp);
        }
+
+       if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD1_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD1_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD2_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD2_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD3_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD3_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD4_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD4_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD5_INT_CONTROL, tmp);
+       }
+       if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+               tmp = RREG32(DC_HPD5_INT_CONTROL);
+               tmp |= DC_HPDx_RX_INT_ACK;
+               WREG32(DC_HPD6_INT_CONTROL, tmp);
+       }
 }
 
 static void si_irq_disable(struct radeon_device *rdev)
@@ -6371,6 +6432,7 @@ int si_irq_process(struct radeon_device *rdev)
        u32 src_id, src_data, ring_id;
        u32 ring_index;
        bool queue_hotplug = false;
+       bool queue_dp = false;
        bool queue_thermal = false;
        u32 status, addr;
 
@@ -6611,6 +6673,48 @@ restart_ih:
                                        DRM_DEBUG("IH: HPD6\n");
                                }
                                break;
+                       case 6:
+                               if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 1\n");
+                               }
+                               break;
+                       case 7:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 2\n");
+                               }
+                               break;
+                       case 8:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 3\n");
+                               }
+                               break;
+                       case 9:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 4\n");
+                               }
+                               break;
+                       case 10:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 5\n");
+                               }
+                               break;
+                       case 11:
+                               if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
+                                       rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
+                                       queue_dp = true;
+                                       DRM_DEBUG("IH: HPD_RX 6\n");
+                               }
+                               break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
                                break;
@@ -6693,6 +6797,8 @@ restart_ih:
                rptr &= rdev->ih.ptr_mask;
                WREG32(IH_RB_RPTR, rptr);
        }
+       if (queue_dp)
+               schedule_work(&rdev->dp_work);
        if (queue_hotplug)
                schedule_work(&rdev->hotplug_work);
        if (queue_thermal && rdev->pm.dpm_enabled)
index 7be11651b7e6c8e5fded976e33ea1ba65ace4775..b35bccfeef79c402c33b6406e0e70755fd4098ad 100644 (file)
@@ -6993,3 +6993,39 @@ void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                           current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci, pl->pcie_gen + 1);
        }
 }
+
+u32 si_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct ni_ps *ps = ni_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
+               CURRENT_STATE_INDEX_SHIFT;
+
+       if (current_index >= ps->performance_level_count) {
+               return 0;
+       } else {
+               pl = &ps->performance_levels[current_index];
+               return pl->sclk;
+       }
+}
+
+u32 si_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct ni_ps *ps = ni_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
+               CURRENT_STATE_INDEX_SHIFT;
+
+       if (current_index >= ps->performance_level_count) {
+               return 0;
+       } else {
+               pl = &ps->performance_levels[current_index];
+               return pl->mclk;
+       }
+}
index 99a9835c9f615919c063af1ce0ca0e596aed8c15..3afac301398388315f78d6cb7cb62e84e7314581 100644 (file)
 #define UVD_UDEC_DBW_ADDR_CONFIG                       0xEF54
 #define UVD_RBC_RB_RPTR                                        0xF690
 #define UVD_RBC_RB_WPTR                                        0xF694
+#define UVD_STATUS                                     0xf6bc
 
 #define        UVD_CGC_CTRL                                    0xF4B0
 #      define DCM                                      (1 << 0)
index 25fd4ced36c83491b4cbfb841a57f30c3ae65130..cd0862809adff2f2749f90eff0b85007cc5e1d4f 100644 (file)
@@ -1837,6 +1837,34 @@ void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev
        }
 }
 
+u32 sumo_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct sumo_power_info *pi = sumo_get_pi(rdev);
+       struct radeon_ps *rps = &pi->current_rps;
+       struct sumo_ps *ps = sumo_get_ps(rps);
+       struct sumo_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) >>
+               CURR_INDEX_SHIFT;
+
+       if (current_index == BOOST_DPM_LEVEL) {
+               pl = &pi->boost_pl;
+               return pl->sclk;
+       } else if (current_index >= ps->num_levels) {
+               return 0;
+       } else {
+               pl = &ps->levels[current_index];
+               return pl->sclk;
+       }
+}
+
+u32 sumo_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+       return pi->sys_info.bootup_uma_clk;
+}
+
 void sumo_dpm_fini(struct radeon_device *rdev)
 {
        int i;
index 38dacb7a3689e80c3ae41eb4c1826442e792ea79..a5b02c575d775b7b1a4409142507470e7f3fc415 100644 (file)
@@ -1964,6 +1964,31 @@ void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *r
        }
 }
 
+u32 trinity_dpm_get_current_sclk(struct radeon_device *rdev)
+{
+       struct trinity_power_info *pi = trinity_get_pi(rdev);
+       struct radeon_ps *rps = &pi->current_rps;
+       struct trinity_ps *ps = trinity_get_ps(rps);
+       struct trinity_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) >>
+               CURRENT_STATE_SHIFT;
+
+       if (current_index >= ps->num_levels) {
+               return 0;
+       } else {
+               pl = &ps->levels[current_index];
+               return pl->sclk;
+       }
+}
+
+u32 trinity_dpm_get_current_mclk(struct radeon_device *rdev)
+{
+       struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+       return pi->sys_info.bootup_uma_clk;
+}
+
 void trinity_dpm_fini(struct radeon_device *rdev)
 {
        int i;
index 1ac7bb825a1b3bfecea601d76f8e33c2b8d581ff..fbbe78fbd087ae7c147a43b925f0ac0401c86466 100644 (file)
@@ -156,6 +156,9 @@ int vce_v2_0_resume(struct radeon_device *rdev)
        WREG32(VCE_LMI_SWAP_CNTL1, 0);
        WREG32(VCE_LMI_VM_CTRL, 0);
 
+       WREG32(VCE_LMI_VCPU_CACHE_40BIT_BAR, addr >> 8);
+
+       addr &= 0xff;
        size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size);
        WREG32(VCE_VCPU_CACHE_OFFSET0, addr & 0x7fffffff);
        WREG32(VCE_VCPU_CACHE_SIZE0, size);
index 9e72133bb64b9ca37bb849e370e57dcbc215ab46..7d0b8ef9bea21ca04a7fc678f3913dc1768615fd 100644 (file)
@@ -486,8 +486,6 @@ static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc)
        unsigned long flags;
 
        if (event) {
-               event->pipe = rcrtc->index;
-
                WARN_ON(drm_crtc_vblank_get(crtc) != 0);
 
                spin_lock_irqsave(&dev->event_lock, flags);
index 1d9e4f8568aebdfb7313e0bfe4e184e40d7a343c..da1216a73969ef62f062486734d5946082ee093f 100644 (file)
@@ -252,7 +252,8 @@ static const struct file_operations rcar_du_fops = {
 };
 
 static struct drm_driver rcar_du_driver = {
-       .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME,
+       .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME
+                               | DRIVER_ATOMIC,
        .load                   = rcar_du_load,
        .unload                 = rcar_du_unload,
        .preclose               = rcar_du_preclose,
index fb052bca574fdd0a71814db3e683c6fa396d038d..93117f159a3ba668c59db1fd6466afd732c4675d 100644 (file)
@@ -509,7 +509,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
        enum rcar_du_encoder_type enc_type = RCAR_DU_ENCODER_NONE;
        struct device_node *connector = NULL;
        struct device_node *encoder = NULL;
-       struct device_node *prev = NULL;
+       struct device_node *ep_node = NULL;
        struct device_node *entity_ep_node;
        struct device_node *entity;
        int ret;
@@ -527,16 +527,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
 
        entity_ep_node = of_parse_phandle(ep->local_node, "remote-endpoint", 0);
 
-       while (1) {
-               struct device_node *ep_node;
-
-               ep_node = of_graph_get_next_endpoint(entity, prev);
-               of_node_put(prev);
-               prev = ep_node;
-
-               if (!ep_node)
-                       break;
-
+       for_each_endpoint_of_node(entity, ep_node) {
                if (ep_node == entity_ep_node)
                        continue;
 
@@ -603,27 +594,19 @@ static int rcar_du_encoders_init_one(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;
+       struct device_node *ep_node;
        unsigned int num_encoders = 0;
 
        /*
         * Iterate over the endpoints and create one encoder for each output
         * pipeline.
         */
-       while (1) {
-               struct device_node *ep_node;
+       for_each_endpoint_of_node(np, ep_node) {
                enum rcar_du_output output;
                struct of_endpoint ep;
                unsigned int i;
                int ret;
 
-               ep_node = of_graph_get_next_endpoint(np, prev);
-               of_node_put(prev);
-               prev = ep_node;
-
-               if (ep_node == NULL)
-                       break;
-
                ret = of_graph_parse_endpoint(ep_node, &ep);
                if (ret < 0) {
                        of_node_put(ep_node);
index 35a2f04ab799a9afe78fb6de14d10b04c645d1d5..210e5c3fd9820d30f3347ce01fb4ecbb8b9f5fe5 100644 (file)
@@ -316,6 +316,9 @@ rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane)
 static void rcar_du_plane_atomic_destroy_state(struct drm_plane *plane,
                                               struct drm_plane_state *state)
 {
+       if (state->fb)
+               drm_framebuffer_unreference(state->fb);
+
        kfree(to_rcar_du_plane_state(state));
 }
 
index d236faa05b1956c2d2f3c4cd9066d66d7c71c391..80d6fc8a5cee4972da16d74ddf1786c2842131fa 100644 (file)
@@ -133,12 +133,12 @@ static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
        }
 };
 
-static const struct dw_hdmi_sym_term rockchip_sym_term[] = {
-       /*pixelclk   symbol   term*/
-       { 74250000,  0x8009, 0x0004 },
-       { 148500000, 0x8029, 0x0004 },
-       { 297000000, 0x8039, 0x0005 },
-       { ~0UL,      0x0000, 0x0000 }
+static const struct dw_hdmi_phy_config rockchip_phy_config[] = {
+       /*pixelclk   symbol   term   vlev*/
+       { 74250000,  0x8009, 0x0004, 0x0272},
+       { 148500000, 0x802b, 0x0004, 0x028d},
+       { 297000000, 0x8039, 0x0005, 0x028d},
+       { ~0UL,      0x0000, 0x0000, 0x0000}
 };
 
 static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
@@ -230,7 +230,7 @@ static const struct dw_hdmi_plat_data rockchip_hdmi_drv_data = {
        .mode_valid = dw_hdmi_rockchip_mode_valid,
        .mpll_cfg   = rockchip_mpll_cfg,
        .cur_ctr    = rockchip_cur_ctr,
-       .sym_term   = rockchip_sym_term,
+       .phy_config = rockchip_phy_config,
        .dev_type   = RK3288_HDMI,
 };
 
index 21a481b224ebab6ef896bbbf5e2a9036c5cfb0ed..3962176ee71325ca4434fa34643f117c58b2d217 100644 (file)
@@ -129,6 +129,7 @@ static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags)
        struct rockchip_drm_private *private;
        struct dma_iommu_mapping *mapping;
        struct device *dev = drm_dev->dev;
+       struct drm_connector *connector;
        int ret;
 
        private = devm_kzalloc(drm_dev->dev, sizeof(*private), GFP_KERNEL);
@@ -171,6 +172,23 @@ static int rockchip_drm_load(struct drm_device *drm_dev, unsigned long flags)
        if (ret)
                goto err_detach_device;
 
+       /*
+        * 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_dev->mode_config.connector_list,
+                       head) {
+               ret = drm_connector_register(connector);
+               if (ret) {
+                       dev_err(drm_dev->dev,
+                               "[CONNECTOR:%d:%s] drm_connector_register failed: %d\n",
+                               connector->base.id,
+                               connector->name, ret);
+                       goto err_unbind;
+               }
+       }
+
        /* init kms poll for handling hpd */
        drm_kms_helper_poll_init(drm_dev);
 
@@ -200,6 +218,7 @@ err_vblank_cleanup:
        drm_vblank_cleanup(drm_dev);
 err_kms_helper_poll_fini:
        drm_kms_helper_poll_fini(drm_dev);
+err_unbind:
        component_unbind_all(dev, drm_dev);
 err_detach_device:
        arm_iommu_detach_device(dev);
@@ -366,7 +385,7 @@ static const struct dev_pm_ops rockchip_drm_pm_ops = {
 int rockchip_drm_encoder_get_mux_id(struct device_node *node,
                                    struct drm_encoder *encoder)
 {
-       struct device_node *ep = NULL;
+       struct device_node *ep;
        struct drm_crtc *crtc = encoder->crtc;
        struct of_endpoint endpoint;
        struct device_node *port;
@@ -375,18 +394,15 @@ int rockchip_drm_encoder_get_mux_id(struct device_node *node,
        if (!node || !crtc)
                return -EINVAL;
 
-       do {
-               ep = of_graph_get_next_endpoint(node, ep);
-               if (!ep)
-                       break;
-
+       for_each_endpoint_of_node(node, ep) {
                port = of_graph_get_remote_port(ep);
                of_node_put(port);
                if (port == crtc->port) {
                        ret = of_graph_parse_endpoint(ep, &endpoint);
+                       of_node_put(ep);
                        return ret ?: endpoint.id;
                }
-       } while (ep);
+       }
 
        return -EINVAL;
 }
index a5d889a8716bd776274462af116d873163ac5f87..5b0dc0f6fd940f7d6689f832e03c0c3cd1048656 100644 (file)
@@ -71,7 +71,7 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,
 
        size = mode_cmd.pitches[0] * mode_cmd.height;
 
-       rk_obj = rockchip_gem_create_object(dev, size);
+       rk_obj = rockchip_gem_create_object(dev, size, true);
        if (IS_ERR(rk_obj))
                return -ENOMEM;
 
@@ -106,7 +106,7 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,
 
        fb = helper->fb;
        drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
-       drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
+       drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
 
        offset = fbi->var.xoffset * bytes_per_pixel;
        offset += fbi->var.yoffset * fb->pitches[0];
@@ -119,6 +119,9 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,
        DRM_DEBUG_KMS("FB [%dx%d]-%d kvaddr=%p offset=%ld size=%d\n",
                      fb->width, fb->height, fb->depth, rk_obj->kvaddr,
                      offset, size);
+
+       fbi->skip_vt_switch = true;
+
        return 0;
 
 err_drm_framebuffer_unref:
index 7ca8799ef78498ca84cc3a48f1265d2f1ce2f6c9..eb2282cc4a56507819a5ab638af504499157157a 100644 (file)
@@ -22,7 +22,8 @@
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_gem.h"
 
-static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj)
+static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj,
+                                 bool alloc_kmap)
 {
        struct drm_gem_object *obj = &rk_obj->base;
        struct drm_device *drm = obj->dev;
@@ -30,7 +31,9 @@ static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj)
        init_dma_attrs(&rk_obj->dma_attrs);
        dma_set_attr(DMA_ATTR_WRITE_COMBINE, &rk_obj->dma_attrs);
 
-       /* TODO(djkurtz): Use DMA_ATTR_NO_KERNEL_MAPPING except for fbdev */
+       if (!alloc_kmap)
+               dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs);
+
        rk_obj->kvaddr = dma_alloc_attrs(drm->dev, obj->size,
                                         &rk_obj->dma_addr, GFP_KERNEL,
                                         &rk_obj->dma_attrs);
@@ -103,7 +106,8 @@ int rockchip_gem_mmap(struct file *filp, struct vm_area_struct *vma)
 }
 
 struct rockchip_gem_object *
-       rockchip_gem_create_object(struct drm_device *drm, unsigned int size)
+       rockchip_gem_create_object(struct drm_device *drm, unsigned int size,
+                                  bool alloc_kmap)
 {
        struct rockchip_gem_object *rk_obj;
        struct drm_gem_object *obj;
@@ -119,7 +123,7 @@ struct rockchip_gem_object *
 
        drm_gem_private_object_init(drm, obj, size);
 
-       ret = rockchip_gem_alloc_buf(rk_obj);
+       ret = rockchip_gem_alloc_buf(rk_obj, alloc_kmap);
        if (ret)
                goto err_free_rk_obj;
 
@@ -163,7 +167,7 @@ rockchip_gem_create_with_handle(struct drm_file *file_priv,
        struct drm_gem_object *obj;
        int ret;
 
-       rk_obj = rockchip_gem_create_object(drm, size);
+       rk_obj = rockchip_gem_create_object(drm, size, false);
        if (IS_ERR(rk_obj))
                return ERR_CAST(rk_obj);
 
@@ -282,6 +286,9 @@ void *rockchip_gem_prime_vmap(struct drm_gem_object *obj)
 {
        struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
 
+       if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs))
+               return NULL;
+
        return rk_obj->kvaddr;
 }
 
index 67bcebe90003dbf5674e752aadd86f9041d6844a..ad22618473a488b10a10e1155f85bc79e1c8870e 100644 (file)
@@ -41,7 +41,8 @@ int rockchip_gem_mmap_buf(struct drm_gem_object *obj,
                          struct vm_area_struct *vma);
 
 struct rockchip_gem_object *
-       rockchip_gem_create_object(struct drm_device *drm, unsigned int size);
+       rockchip_gem_create_object(struct drm_device *drm, unsigned int size,
+                                  bool alloc_kmap);
 
 void rockchip_gem_free_object(struct drm_gem_object *obj);
 
index 9a5c571b95fceb97dae7bfadf1b9782ede0f686e..ccb0ce073ef2af6f2233fbc88428ea176dbea855 100644 (file)
@@ -81,7 +81,7 @@ struct vop {
        struct drm_crtc crtc;
        struct device *dev;
        struct drm_device *drm_dev;
-       unsigned int dpms;
+       bool is_enabled;
 
        int connector_type;
        int connector_out_mode;
@@ -89,6 +89,7 @@ struct vop {
        /* mutex vsync_ work */
        struct mutex vsync_mutex;
        bool vsync_work_pending;
+       struct completion dsp_hold_completion;
 
        const struct vop_data *data;
 
@@ -382,11 +383,50 @@ static bool is_alpha_support(uint32_t format)
        }
 }
 
+static void vop_dsp_hold_valid_irq_enable(struct vop *vop)
+{
+       unsigned long flags;
+
+       if (WARN_ON(!vop->is_enabled))
+               return;
+
+       spin_lock_irqsave(&vop->irq_lock, flags);
+
+       vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK,
+                      DSP_HOLD_VALID_INTR_EN(1));
+
+       spin_unlock_irqrestore(&vop->irq_lock, flags);
+}
+
+static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
+{
+       unsigned long flags;
+
+       if (WARN_ON(!vop->is_enabled))
+               return;
+
+       spin_lock_irqsave(&vop->irq_lock, flags);
+
+       vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK,
+                      DSP_HOLD_VALID_INTR_EN(0));
+
+       spin_unlock_irqrestore(&vop->irq_lock, flags);
+}
+
 static void vop_enable(struct drm_crtc *crtc)
 {
        struct vop *vop = to_vop(crtc);
        int ret;
 
+       if (vop->is_enabled)
+               return;
+
+       ret = pm_runtime_get_sync(vop->dev);
+       if (ret < 0) {
+               dev_err(vop->dev, "failed to get pm runtime: %d\n", ret);
+               return;
+       }
+
        ret = clk_enable(vop->hclk);
        if (ret < 0) {
                dev_err(vop->dev, "failed to enable hclk - %d\n", ret);
@@ -417,6 +457,11 @@ static void vop_enable(struct drm_crtc *crtc)
                goto err_disable_aclk;
        }
 
+       /*
+        * At here, vop clock & iommu is enable, R/W vop regs would be safe.
+        */
+       vop->is_enabled = true;
+
        spin_lock(&vop->reg_lock);
 
        VOP_CTRL_SET(vop, standby, 0);
@@ -441,28 +486,44 @@ static void vop_disable(struct drm_crtc *crtc)
 {
        struct vop *vop = to_vop(crtc);
 
-       drm_vblank_off(crtc->dev, vop->pipe);
+       if (!vop->is_enabled)
+               return;
 
-       disable_irq(vop->irq);
+       drm_vblank_off(crtc->dev, vop->pipe);
 
        /*
-        * TODO: Since standby doesn't take effect until the next vblank,
-        * when we turn off dclk below, the vop is probably still active.
+        * Vop standby will take effect at end of current frame,
+        * if dsp hold valid irq happen, it means standby complete.
+        *
+        * we must wait standby complete when we want to disable aclk,
+        * if not, memory bus maybe dead.
         */
+       reinit_completion(&vop->dsp_hold_completion);
+       vop_dsp_hold_valid_irq_enable(vop);
+
        spin_lock(&vop->reg_lock);
 
        VOP_CTRL_SET(vop, standby, 1);
 
        spin_unlock(&vop->reg_lock);
+
+       wait_for_completion(&vop->dsp_hold_completion);
+
+       vop_dsp_hold_valid_irq_disable(vop);
+
+       disable_irq(vop->irq);
+
+       vop->is_enabled = false;
+
        /*
-        * disable dclk to stop frame scan, so we can safely detach iommu,
+        * vop standby complete, so iommu detach is safe.
         */
-       clk_disable(vop->dclk);
-
        rockchip_drm_dma_detach_device(vop->drm_dev, vop->dev);
 
+       clk_disable(vop->dclk);
        clk_disable(vop->aclk);
        clk_disable(vop->hclk);
+       pm_runtime_put(vop->dev);
 }
 
 /*
@@ -742,7 +803,7 @@ static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
        struct vop *vop = to_vop(crtc);
        unsigned long flags;
 
-       if (vop->dpms != DRM_MODE_DPMS_ON)
+       if (!vop->is_enabled)
                return -EPERM;
 
        spin_lock_irqsave(&vop->irq_lock, flags);
@@ -759,8 +820,9 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc)
        struct vop *vop = to_vop(crtc);
        unsigned long flags;
 
-       if (vop->dpms != DRM_MODE_DPMS_ON)
+       if (!vop->is_enabled)
                return;
+
        spin_lock_irqsave(&vop->irq_lock, flags);
        vop_mask_write(vop, INTR_CTRL0, FS_INTR_MASK, FS_INTR_EN(0));
        spin_unlock_irqrestore(&vop->irq_lock, flags);
@@ -773,15 +835,8 @@ static const struct rockchip_crtc_funcs private_crtc_funcs = {
 
 static void vop_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
-       struct vop *vop = to_vop(crtc);
-
        DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
 
-       if (vop->dpms == mode) {
-               DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
-               return;
-       }
-
        switch (mode) {
        case DRM_MODE_DPMS_ON:
                vop_enable(crtc);
@@ -795,8 +850,6 @@ static void vop_crtc_dpms(struct drm_crtc *crtc, int mode)
                DRM_DEBUG_KMS("unspecified mode %d\n", mode);
                break;
        }
-
-       vop->dpms = mode;
 }
 
 static void vop_crtc_prepare(struct drm_crtc *crtc)
@@ -847,7 +900,7 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
        u16 vsync_len = adjusted_mode->vsync_end - adjusted_mode->vsync_start;
        u16 vact_st = adjusted_mode->vtotal - adjusted_mode->vsync_start;
        u16 vact_end = vact_st + vdisplay;
-       int ret;
+       int ret, ret_clk;
        uint32_t val;
 
        /*
@@ -869,13 +922,14 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
        default:
                DRM_ERROR("unsupport connector_type[%d]\n",
                          vop->connector_type);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        };
        VOP_CTRL_SET(vop, out_mode, vop->connector_out_mode);
 
        val = 0x8;
-       val |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0;
-       val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? (1 << 1) : 0;
+       val |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1;
+       val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1);
        VOP_CTRL_SET(vop, pin_pol, val);
 
        VOP_CTRL_SET(vop, htotal_pw, (htotal << 16) | hsync_len);
@@ -892,7 +946,7 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
 
        ret = vop_crtc_mode_set_base(crtc, x, y, fb);
        if (ret)
-               return ret;
+               goto out;
 
        /*
         * reset dclk, take all mode config affect, so the clk would run in
@@ -903,13 +957,14 @@ static int vop_crtc_mode_set(struct drm_crtc *crtc,
        reset_control_deassert(vop->dclk_rst);
 
        clk_set_rate(vop->dclk, adjusted_mode->clock * 1000);
-       ret = clk_enable(vop->dclk);
-       if (ret < 0) {
-               dev_err(vop->dev, "failed to enable dclk - %d\n", ret);
-               return ret;
+out:
+       ret_clk = clk_enable(vop->dclk);
+       if (ret_clk < 0) {
+               dev_err(vop->dev, "failed to enable dclk - %d\n", ret_clk);
+               return ret_clk;
        }
 
-       return 0;
+       return ret;
 }
 
 static void vop_crtc_commit(struct drm_crtc *crtc)
@@ -934,9 +989,9 @@ static int vop_crtc_page_flip(struct drm_crtc *crtc,
        struct drm_framebuffer *old_fb = crtc->primary->fb;
        int ret;
 
-       /* when the page flip is requested, crtc's dpms should be on */
-       if (vop->dpms > DRM_MODE_DPMS_ON) {
-               DRM_DEBUG("failed page flip request at dpms[%d].\n", vop->dpms);
+       /* when the page flip is requested, crtc should be on */
+       if (!vop->is_enabled) {
+               DRM_DEBUG("page flip request rejected because crtc is off.\n");
                return 0;
        }
 
@@ -1081,6 +1136,7 @@ static irqreturn_t vop_isr(int irq, void *data)
        struct vop *vop = data;
        uint32_t intr0_reg, active_irqs;
        unsigned long flags;
+       int ret = IRQ_NONE;
 
        /*
         * INTR_CTRL0 register has interrupt status, enable and clear bits, we
@@ -1099,15 +1155,23 @@ static irqreturn_t vop_isr(int irq, void *data)
        if (!active_irqs)
                return IRQ_NONE;
 
-       /* Only Frame Start Interrupt is enabled; other irqs are spurious. */
-       if (!(active_irqs & FS_INTR)) {
-               DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs);
-               return IRQ_NONE;
+       if (active_irqs & DSP_HOLD_VALID_INTR) {
+               complete(&vop->dsp_hold_completion);
+               active_irqs &= ~DSP_HOLD_VALID_INTR;
+               ret = IRQ_HANDLED;
+       }
+
+       if (active_irqs & FS_INTR) {
+               drm_handle_vblank(vop->drm_dev, vop->pipe);
+               active_irqs &= ~FS_INTR;
+               ret = (vop->vsync_work_pending) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
        }
 
-       drm_handle_vblank(vop->drm_dev, vop->pipe);
+       /* Unhandled irqs are spurious. */
+       if (active_irqs)
+               DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs);
 
-       return (vop->vsync_work_pending) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
+       return ret;
 }
 
 static int vop_create_crtc(struct vop *vop)
@@ -1189,6 +1253,7 @@ static int vop_create_crtc(struct vop *vop)
                goto err_cleanup_crtc;
        }
 
+       init_completion(&vop->dsp_hold_completion);
        crtc->port = port;
        vop->pipe = drm_crtc_index(crtc);
        rockchip_register_crtc_funcs(drm_dev, &private_crtc_funcs, vop->pipe);
@@ -1302,7 +1367,7 @@ static int vop_initial(struct vop *vop)
 
        clk_disable(vop->hclk);
 
-       vop->dpms = DRM_MODE_DPMS_OFF;
+       vop->is_enabled = false;
 
        return 0;
 
index e6f6ef7c4866ad94eb7bd503eabc9aee7e2b8181..6b641c5a2ec7d10609f20a38cbe6bab56c9f4c5e 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/clk.h>
 
 #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>
 
@@ -77,22 +79,18 @@ static bool sti_drm_crtc_mode_fixup(struct drm_crtc *crtc,
 }
 
 static int
-sti_drm_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)
+sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode)
 {
        struct sti_mixer *mixer = to_sti_mixer(crtc);
        struct device *dev = mixer->dev;
        struct sti_compositor *compo = dev_get_drvdata(dev);
-       struct sti_layer *layer;
        struct clk *clk;
        int rate = mode->clock * 1000;
        int res;
-       unsigned int w, h;
 
-       DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d mode:%d (%s)\n",
+       DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n",
                      crtc->base.id, sti_mixer_to_str(mixer),
-                     crtc->primary->fb->base.id, mode->base.id, mode->name);
+                     mode->base.id, mode->name);
 
        DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
                      mode->vrefresh, mode->clock,
@@ -122,72 +120,13 @@ sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
        sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ?
                        compo->vtg_main : compo->vtg_aux, &crtc->mode);
 
-       /* a GDP is reserved to the CRTC FB */
-       layer = to_sti_layer(crtc->primary);
-       if (!layer) {
-               DRM_ERROR("Can not find GDP0)\n");
-               return -EINVAL;
-       }
-
-       /* copy the mode data adjusted by mode_fixup() into crtc->mode
-        * so that hardware can be set to proper mode
-        */
-       memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
-
-       res = sti_mixer_set_layer_depth(mixer, layer);
-       if (res) {
-               DRM_ERROR("Can not set layer depth\n");
-               return -EINVAL;
-       }
        res = sti_mixer_active_video_area(mixer, &crtc->mode);
        if (res) {
                DRM_ERROR("Can not set active video area\n");
                return -EINVAL;
        }
 
-       w = crtc->primary->fb->width - x;
-       h = crtc->primary->fb->height - y;
-
-       return sti_layer_prepare(layer, crtc,
-                       crtc->primary->fb, &crtc->mode,
-                       mixer->id, 0, 0, w, h, x, y, w, h);
-}
-
-static int sti_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
-                                     struct drm_framebuffer *old_fb)
-{
-       struct sti_mixer *mixer = to_sti_mixer(crtc);
-       struct sti_layer *layer;
-       unsigned int w, h;
-       int ret;
-
-       DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d (%d,%d)\n",
-                     crtc->base.id, sti_mixer_to_str(mixer),
-                     crtc->primary->fb->base.id, x, y);
-
-       /* GDP is reserved to the CRTC FB */
-       layer = to_sti_layer(crtc->primary);
-       if (!layer) {
-               DRM_ERROR("Can not find GDP0)\n");
-               ret = -EINVAL;
-               goto out;
-       }
-
-       w = crtc->primary->fb->width - crtc->x;
-       h = crtc->primary->fb->height - crtc->y;
-
-       ret = sti_layer_prepare(layer, crtc,
-                               crtc->primary->fb, &crtc->mode,
-                               mixer->id, 0, 0, w, h,
-                               crtc->x, crtc->y, w, h);
-       if (ret) {
-               DRM_ERROR("Can not prepare layer\n");
-               goto out;
-       }
-
-       sti_drm_crtc_commit(crtc);
-out:
-       return ret;
+       return res;
 }
 
 static void sti_drm_crtc_disable(struct drm_crtc *crtc)
@@ -195,7 +134,6 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc)
        struct sti_mixer *mixer = to_sti_mixer(crtc);
        struct device *dev = mixer->dev;
        struct sti_compositor *compo = dev_get_drvdata(dev);
-       struct sti_layer *layer;
 
        if (!mixer->enabled)
                return;
@@ -205,24 +143,6 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc)
        /* Disable Background */
        sti_mixer_set_background_status(mixer, false);
 
-       /* Disable GDP */
-       layer = to_sti_layer(crtc->primary);
-       if (!layer) {
-               DRM_ERROR("Cannot find GDP0\n");
-               return;
-       }
-
-       /* Disable layer at mixer level */
-       if (sti_mixer_set_layer_status(mixer, layer, false))
-               DRM_ERROR("Can not disable %s layer at mixer\n",
-                               sti_layer_to_str(layer));
-
-       /* Wait a while to be sure that a Vsync event is received */
-       msleep(WAIT_NEXT_VSYNC_MS);
-
-       /* Then disable layer itself */
-       sti_layer_disable(layer);
-
        drm_crtc_vblank_off(crtc);
 
        /* Disable pixel clock and compo IP clocks */
@@ -237,64 +157,44 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc)
        mixer->enabled = false;
 }
 
-static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
-       .dpms = sti_drm_crtc_dpms,
-       .prepare = sti_drm_crtc_prepare,
-       .commit = sti_drm_crtc_commit,
-       .mode_fixup = sti_drm_crtc_mode_fixup,
-       .mode_set = sti_drm_crtc_mode_set,
-       .mode_set_base = sti_drm_crtc_mode_set_base,
-       .disable = sti_drm_crtc_disable,
-};
+static void
+sti_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+       sti_drm_crtc_prepare(crtc);
+       sti_drm_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
+}
 
-static int sti_drm_crtc_page_flip(struct drm_crtc *crtc,
-                                 struct drm_framebuffer *fb,
-                                 struct drm_pending_vblank_event *event,
-                                 uint32_t page_flip_flags)
+static void sti_drm_atomic_begin(struct drm_crtc *crtc)
 {
-       struct drm_device *drm_dev = crtc->dev;
-       struct drm_framebuffer *old_fb;
        struct sti_mixer *mixer = to_sti_mixer(crtc);
-       unsigned long flags;
-       int ret;
 
-       DRM_DEBUG_KMS("fb %d --> fb %d\n",
-                       crtc->primary->fb->base.id, fb->base.id);
+       if (crtc->state->event) {
+               crtc->state->event->pipe = drm_crtc_index(crtc);
 
-       mutex_lock(&drm_dev->struct_mutex);
+               WARN_ON(drm_crtc_vblank_get(crtc) != 0);
 
-       old_fb = crtc->primary->fb;
-       crtc->primary->fb = fb;
-       ret = sti_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb);
-       if (ret) {
-               DRM_ERROR("failed\n");
-               crtc->primary->fb = old_fb;
-               goto out;
+               mixer->pending_event = crtc->state->event;
+               crtc->state->event = NULL;
        }
+}
 
-       if (event) {
-               event->pipe = mixer->id;
-
-               ret = drm_vblank_get(drm_dev, event->pipe);
-               if (ret) {
-                       DRM_ERROR("Cannot get vblank\n");
-                       goto out;
-               }
-
-               spin_lock_irqsave(&drm_dev->event_lock, flags);
-               if (mixer->pending_event) {
-                       drm_vblank_put(drm_dev, event->pipe);
-                       ret = -EBUSY;
-               } else {
-                       mixer->pending_event = event;
-               }
-               spin_unlock_irqrestore(&drm_dev->event_lock, flags);
-       }
-out:
-       mutex_unlock(&drm_dev->struct_mutex);
-       return ret;
+static void sti_drm_atomic_flush(struct drm_crtc *crtc)
+{
 }
 
+static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
+       .dpms = sti_drm_crtc_dpms,
+       .prepare = sti_drm_crtc_prepare,
+       .commit = sti_drm_crtc_commit,
+       .mode_fixup = sti_drm_crtc_mode_fixup,
+       .mode_set = drm_helper_crtc_mode_set,
+       .mode_set_nofb = sti_drm_crtc_mode_set_nofb,
+       .mode_set_base = drm_helper_crtc_mode_set_base,
+       .disable = sti_drm_crtc_disable,
+       .atomic_begin = sti_drm_atomic_begin,
+       .atomic_flush = sti_drm_atomic_flush,
+};
+
 static void sti_drm_crtc_destroy(struct drm_crtc *crtc)
 {
        DRM_DEBUG_KMS("\n");
@@ -380,10 +280,13 @@ void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
 EXPORT_SYMBOL(sti_drm_crtc_disable_vblank);
 
 static struct drm_crtc_funcs sti_crtc_funcs = {
-       .set_config = drm_crtc_helper_set_config,
-       .page_flip = sti_drm_crtc_page_flip,
+       .set_config = drm_atomic_helper_set_config,
+       .page_flip = drm_atomic_helper_page_flip,
        .destroy = sti_drm_crtc_destroy,
        .set_property = sti_drm_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,
 };
 
 bool sti_drm_crtc_is_main(struct drm_crtc *crtc)
index 5239fa12172683cd2313e3863107acc26c7c08c0..59d558b400b33f390cdd6db00014ab29c94b84d4 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/module.h>
 #include <linux/of_platform.h>
 
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #define STI_MAX_FB_HEIGHT      4096
 #define STI_MAX_FB_WIDTH       4096
 
+static void sti_drm_atomic_schedule(struct sti_drm_private *private,
+                                 struct drm_atomic_state *state)
+{
+       private->commit.state = state;
+       schedule_work(&private->commit.work);
+}
+
+static void sti_drm_atomic_complete(struct sti_drm_private *private,
+                                 struct drm_atomic_state *state)
+{
+       struct drm_device *drm = private->drm_dev;
+
+       /*
+        * Everything below can be run asynchronously without the need to grab
+        * any modeset locks at all under one condition: 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.
+        */
+
+       drm_atomic_helper_commit_modeset_disables(drm, state);
+       drm_atomic_helper_commit_planes(drm, state);
+       drm_atomic_helper_commit_modeset_enables(drm, state);
+
+       drm_atomic_helper_wait_for_vblanks(drm, state);
+
+       drm_atomic_helper_cleanup_planes(drm, state);
+       drm_atomic_state_free(state);
+}
+
+static void sti_drm_atomic_work(struct work_struct *work)
+{
+       struct sti_drm_private *private = container_of(work,
+                       struct sti_drm_private, commit.work);
+
+       sti_drm_atomic_complete(private, private->commit.state);
+}
+
+static int sti_drm_atomic_commit(struct drm_device *drm,
+                              struct drm_atomic_state *state, bool async)
+{
+       struct sti_drm_private *private = drm->dev_private;
+       int err;
+
+       err = drm_atomic_helper_prepare_planes(drm, state);
+       if (err)
+               return err;
+
+       /* serialize outstanding asynchronous commits */
+       mutex_lock(&private->commit.lock);
+       flush_work(&private->commit.work);
+
+       /*
+        * 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(drm, state);
+
+       if (async)
+               sti_drm_atomic_schedule(private, state);
+       else
+               sti_drm_atomic_complete(private, state);
+
+       mutex_unlock(&private->commit.lock);
+       return 0;
+}
+
 static struct drm_mode_config_funcs sti_drm_mode_config_funcs = {
        .fb_create = drm_fb_cma_create,
+       .atomic_check = drm_atomic_helper_check,
+       .atomic_commit = sti_drm_atomic_commit,
 };
 
 static void sti_drm_mode_config_init(struct drm_device *dev)
@@ -61,6 +142,9 @@ static int sti_drm_load(struct drm_device *dev, unsigned long flags)
        dev->dev_private = (void *)private;
        private->drm_dev = dev;
 
+       mutex_init(&private->commit.lock);
+       INIT_WORK(&private->commit.work, sti_drm_atomic_work);
+
        drm_mode_config_init(dev);
        drm_kms_helper_poll_init(dev);
 
@@ -74,7 +158,7 @@ static int sti_drm_load(struct drm_device *dev, unsigned long flags)
                return ret;
        }
 
-       drm_helper_disable_unused_functions(dev);
+       drm_mode_config_reset(dev);
 
 #ifdef CONFIG_DRM_STI_FBDEV
        drm_fbdev_cma_init(dev, 32,
index ec5e2eb8dff91e24cc5c0a7321012b4b93d158ff..c413aa3ff4021449791f3ce73668d8beabdb94c9 100644 (file)
@@ -24,6 +24,12 @@ struct sti_drm_private {
        struct sti_compositor *compo;
        struct drm_property *plane_zorder_property;
        struct drm_device *drm_dev;
+
+       struct {
+               struct drm_atomic_state *state;
+               struct work_struct work;
+               struct mutex lock;
+       } commit;
 };
 
 #endif
index bb6a29339e1084bca0483e7ee643cfc62c06299a..64d4ed43dda3fa6e38a81a7bb4ba9bafba02287a 100644 (file)
@@ -6,6 +6,10 @@
  * License terms:  GNU General Public License (GPL), version 2
  */
 
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+
 #include "sti_compositor.h"
 #include "sti_drm_drv.h"
 #include "sti_drm_plane.h"
@@ -33,9 +37,9 @@ sti_drm_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        struct sti_mixer *mixer = to_sti_mixer(crtc);
        int res;
 
-       DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s) drm fb:%d\n",
+       DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
                      crtc->base.id, sti_mixer_to_str(mixer),
-                     plane->base.id, sti_layer_to_str(layer), fb->base.id);
+                     plane->base.id, sti_layer_to_str(layer));
        DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", crtc_w, crtc_h, crtc_x, crtc_y);
 
        res = sti_mixer_set_layer_depth(mixer, layer);
@@ -110,7 +114,7 @@ static void sti_drm_plane_destroy(struct drm_plane *plane)
 {
        DRM_DEBUG_DRIVER("\n");
 
-       sti_drm_disable_plane(plane);
+       drm_plane_helper_disable(plane);
        drm_plane_cleanup(plane);
 }
 
@@ -133,10 +137,58 @@ static int sti_drm_plane_set_property(struct drm_plane *plane,
 }
 
 static struct drm_plane_funcs sti_drm_plane_funcs = {
-       .update_plane = sti_drm_update_plane,
-       .disable_plane = sti_drm_disable_plane,
+       .update_plane = drm_atomic_helper_update_plane,
+       .disable_plane = drm_atomic_helper_disable_plane,
        .destroy = sti_drm_plane_destroy,
        .set_property = sti_drm_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,
+};
+
+static int sti_drm_plane_prepare_fb(struct drm_plane *plane,
+                                 struct drm_framebuffer *fb,
+                                 const struct drm_plane_state *new_state)
+{
+       return 0;
+}
+
+static void sti_drm_plane_cleanup_fb(struct drm_plane *plane,
+                                  struct drm_framebuffer *fb,
+                                  const struct drm_plane_state *old_fb)
+{
+}
+
+static int sti_drm_plane_atomic_check(struct drm_plane *plane,
+                                     struct drm_plane_state *state)
+{
+       return 0;
+}
+
+static void sti_drm_plane_atomic_update(struct drm_plane *plane,
+                                       struct drm_plane_state *oldstate)
+{
+       struct drm_plane_state *state = plane->state;
+
+       sti_drm_update_plane(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);
+}
+
+static void sti_drm_plane_atomic_disable(struct drm_plane *plane,
+                                        struct drm_plane_state *oldstate)
+{
+       sti_drm_disable_plane(plane);
+}
+
+static const struct drm_plane_helper_funcs sti_drm_plane_helpers_funcs = {
+       .prepare_fb = sti_drm_plane_prepare_fb,
+       .cleanup_fb = sti_drm_plane_cleanup_fb,
+       .atomic_check = sti_drm_plane_atomic_check,
+       .atomic_update = sti_drm_plane_atomic_update,
+       .atomic_disable = sti_drm_plane_atomic_disable,
 };
 
 static void sti_drm_plane_attach_zorder_property(struct drm_plane *plane,
@@ -178,11 +230,13 @@ struct drm_plane *sti_drm_plane_init(struct drm_device *dev,
                return NULL;
        }
 
+       drm_plane_helper_add(&layer->plane, &sti_drm_plane_helpers_funcs);
+
        for (i = 0; i < ARRAY_SIZE(sti_layer_default_zorder); i++)
                if (sti_layer_default_zorder[i] == layer->desc)
                        break;
 
-       default_zorder = i;
+       default_zorder = i + 1;
 
        if (type == DRM_PLANE_TYPE_OVERLAY)
                sti_drm_plane_attach_zorder_property(&layer->plane,
index aeb5070c8363fb6307ab7c6c768dab9fefece269..a9b678af85a6f315716fa82871674519e017b9f3 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/platform_device.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_panel.h>
 
@@ -364,10 +365,13 @@ static void sti_dvo_connector_destroy(struct drm_connector *connector)
 }
 
 static struct drm_connector_funcs sti_dvo_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = sti_dvo_connector_detect,
        .destroy = sti_dvo_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 struct drm_encoder *sti_dvo_find_encoder(struct drm_device *dev)
index a9bbb081ecadc1165031b9c794b753d083b9ee2f..598cd78b0b163cd2e86f92a68e5386325a3a357f 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/platform_device.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 
 /* HDformatter registers */
@@ -611,10 +612,13 @@ static void sti_hda_connector_destroy(struct drm_connector *connector)
 }
 
 static struct drm_connector_funcs sti_hda_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = sti_hda_connector_detect,
        .destroy = sti_hda_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 struct drm_encoder *sti_hda_find_encoder(struct drm_device *dev)
index 1485ade98710a3078de14c8b577db2a5bd15cd21..ae5424bd6b4cbd00d1ffc5b4fd35f11cb56a11cd 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/reset.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
 
@@ -663,10 +664,13 @@ static void sti_hdmi_connector_destroy(struct drm_connector *connector)
 }
 
 static struct drm_connector_funcs sti_hdmi_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = sti_hdmi_connector_detect,
        .destroy = sti_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 struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev)
index b7f781573b15e7e2b6b0f3f9a0cf86923b0ff7c2..a287e4fec8653d91e55bb2765e2379984b65bef5 100644 (file)
@@ -425,8 +425,8 @@ static void tegra_plane_reset(struct drm_plane *plane)
 {
        struct tegra_plane_state *state;
 
-       if (plane->state && plane->state->fb)
-               drm_framebuffer_unreference(plane->state->fb);
+       if (plane->state)
+               __drm_atomic_helper_plane_destroy_state(plane, plane->state);
 
        kfree(plane->state);
        plane->state = NULL;
@@ -443,12 +443,14 @@ static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_pla
        struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
        struct tegra_plane_state *copy;
 
-       copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+       copy = kmalloc(sizeof(*copy), GFP_KERNEL);
        if (!copy)
                return NULL;
 
-       if (copy->base.fb)
-               drm_framebuffer_reference(copy->base.fb);
+       __drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
+       copy->tiling = state->tiling;
+       copy->format = state->format;
+       copy->swap = state->swap;
 
        return &copy->base;
 }
@@ -456,9 +458,7 @@ static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_pla
 static void tegra_plane_atomic_destroy_state(struct drm_plane *plane,
                                             struct drm_plane_state *state)
 {
-       if (state->fb)
-               drm_framebuffer_unreference(state->fb);
-
+       __drm_atomic_helper_plane_destroy_state(plane, state);
        kfree(state);
 }
 
@@ -908,6 +908,15 @@ static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
        return 0;
 }
 
+u32 tegra_dc_get_vblank_counter(struct tegra_dc *dc)
+{
+       if (dc->syncpt)
+               return host1x_syncpt_read(dc->syncpt);
+
+       /* fallback to software emulated VBLANK counter */
+       return drm_crtc_vblank_count(&dc->base);
+}
+
 void tegra_dc_enable_vblank(struct tegra_dc *dc)
 {
        unsigned long value, flags;
@@ -995,6 +1004,9 @@ static void tegra_crtc_reset(struct drm_crtc *crtc)
 {
        struct tegra_dc_state *state;
 
+       if (crtc->state)
+               __drm_atomic_helper_crtc_destroy_state(crtc, crtc->state);
+
        kfree(crtc->state);
        crtc->state = NULL;
 
@@ -1011,14 +1023,15 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
        struct tegra_dc_state *state = to_dc_state(crtc->state);
        struct tegra_dc_state *copy;
 
-       copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+       copy = kmalloc(sizeof(*copy), GFP_KERNEL);
        if (!copy)
                return NULL;
 
-       copy->base.mode_changed = false;
-       copy->base.active_changed = false;
-       copy->base.planes_changed = false;
-       copy->base.event = NULL;
+       __drm_atomic_helper_crtc_duplicate_state(crtc, &copy->base);
+       copy->clk = state->clk;
+       copy->pclk = state->pclk;
+       copy->div = state->div;
+       copy->planes = state->planes;
 
        return &copy->base;
 }
@@ -1026,6 +1039,7 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
 static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc,
                                            struct drm_crtc_state *state)
 {
+       __drm_atomic_helper_crtc_destroy_state(crtc, state);
        kfree(state);
 }
 
@@ -1152,26 +1166,18 @@ static int tegra_dc_set_timings(struct tegra_dc *dc,
        return 0;
 }
 
-int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent,
-                        unsigned long pclk, unsigned int div)
-{
-       u32 value;
-       int err;
-
-       err = clk_set_parent(dc->clk, parent);
-       if (err < 0) {
-               dev_err(dc->dev, "failed to set parent clock: %d\n", err);
-               return err;
-       }
-
-       DRM_DEBUG_KMS("rate: %lu, div: %u\n", clk_get_rate(dc->clk), div);
-
-       value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1;
-       tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
-
-       return 0;
-}
-
+/**
+ * tegra_dc_state_setup_clock - check clock settings and store them in atomic
+ *     state
+ * @dc: display controller
+ * @crtc_state: CRTC atomic state
+ * @clk: parent clock for display controller
+ * @pclk: pixel clock
+ * @div: shift clock divider
+ *
+ * Returns:
+ * 0 on success or a negative error-code on failure.
+ */
 int tegra_dc_state_setup_clock(struct tegra_dc *dc,
                               struct drm_crtc_state *crtc_state,
                               struct clk *clk, unsigned long pclk,
@@ -1179,6 +1185,9 @@ int tegra_dc_state_setup_clock(struct tegra_dc *dc,
 {
        struct tegra_dc_state *state = to_dc_state(crtc_state);
 
+       if (!clk_has_parent(dc->clk, clk))
+               return -EINVAL;
+
        state->clk = clk;
        state->pclk = pclk;
        state->div = div;
@@ -1294,9 +1303,7 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc)
 static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {
        .disable = tegra_crtc_disable,
        .mode_fixup = tegra_crtc_mode_fixup,
-       .mode_set = drm_helper_crtc_mode_set,
        .mode_set_nofb = tegra_crtc_mode_set_nofb,
-       .mode_set_base = drm_helper_crtc_mode_set_base,
        .prepare = tegra_crtc_prepare,
        .commit = tegra_crtc_commit,
        .atomic_check = tegra_crtc_atomic_check,
@@ -1631,7 +1638,6 @@ static int tegra_dc_init(struct host1x_client *client)
        struct tegra_drm *tegra = drm->dev_private;
        struct drm_plane *primary = NULL;
        struct drm_plane *cursor = NULL;
-       unsigned int syncpt;
        u32 value;
        int err;
 
@@ -1700,13 +1706,15 @@ static int tegra_dc_init(struct host1x_client *client)
        }
 
        /* initialize display controller */
-       if (dc->pipe)
-               syncpt = SYNCPT_VBLANK1;
-       else
-               syncpt = SYNCPT_VBLANK0;
+       if (dc->syncpt) {
+               u32 syncpt = host1x_syncpt_id(dc->syncpt);
 
-       tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
-       tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC);
+               value = SYNCPT_CNTRL_NO_STALL;
+               tegra_dc_writel(dc, value, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
+
+               value = SYNCPT_VSYNC_ENABLE | syncpt;
+               tegra_dc_writel(dc, value, DC_CMD_CONT_SYNCPT_VSYNC);
+       }
 
        value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT;
        tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);
@@ -1874,6 +1882,7 @@ static int tegra_dc_parse_dt(struct tegra_dc *dc)
 
 static int tegra_dc_probe(struct platform_device *pdev)
 {
+       unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
        const struct of_device_id *id;
        struct resource *regs;
        struct tegra_dc *dc;
@@ -1965,6 +1974,10 @@ static int tegra_dc_probe(struct platform_device *pdev)
                return err;
        }
 
+       dc->syncpt = host1x_syncpt_request(&pdev->dev, flags);
+       if (!dc->syncpt)
+               dev_warn(&pdev->dev, "failed to allocate syncpoint\n");
+
        platform_set_drvdata(pdev, dc);
 
        return 0;
@@ -1975,6 +1988,8 @@ static int tegra_dc_remove(struct platform_device *pdev)
        struct tegra_dc *dc = platform_get_drvdata(pdev);
        int err;
 
+       host1x_syncpt_free(dc->syncpt);
+
        err = host1x_client_unregister(&dc->client);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
index 705c93b00794feb38f56a501b7546f9e6f07b1f9..55792daabbb587b80712c684742c902c1303ee65 100644 (file)
@@ -12,6 +12,8 @@
 
 #define DC_CMD_GENERAL_INCR_SYNCPT             0x000
 #define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL       0x001
+#define  SYNCPT_CNTRL_NO_STALL   (1 << 8)
+#define  SYNCPT_CNTRL_SOFT_RESET (1 << 0)
 #define DC_CMD_GENERAL_INCR_SYNCPT_ERROR       0x002
 #define DC_CMD_WIN_A_INCR_SYNCPT               0x008
 #define DC_CMD_WIN_A_INCR_SYNCPT_CNTRL         0x009
@@ -23,6 +25,7 @@
 #define DC_CMD_WIN_C_INCR_SYNCPT_CNTRL         0x019
 #define DC_CMD_WIN_C_INCR_SYNCPT_ERROR         0x01a
 #define DC_CMD_CONT_SYNCPT_VSYNC               0x028
+#define  SYNCPT_VSYNC_ENABLE (1 << 8)
 #define DC_CMD_DISPLAY_COMMAND_OPTION0         0x031
 #define DC_CMD_DISPLAY_COMMAND                 0x032
 #define DISP_CTRL_MODE_STOP (0 << 5)
 #define DC_WINBUF_BD_UFLOW_STATUS              0xdca
 #define DC_WINBUF_CD_UFLOW_STATUS              0xfca
 
-/* synchronization points */
-#define SYNCPT_VBLANK0 26
-#define SYNCPT_VBLANK1 27
-
 #endif /* TEGRA_DC_H */
index 5f1880766110455034db47d1e21f4e89c7d13e3e..1833abd7d3aafa38c796cc5acb7d3bb9a8356c86 100644 (file)
@@ -172,6 +172,10 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
         */
        drm->irq_enabled = true;
 
+       /* syncpoints are used for full 32-bit hardware VBLANK counters */
+       drm->vblank_disable_immediate = true;
+       drm->max_vblank_count = 0xffffffff;
+
        err = drm_vblank_init(drm, drm->mode_config.num_crtc);
        if (err < 0)
                goto device;
@@ -813,12 +817,12 @@ static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm,
 static u32 tegra_drm_get_vblank_counter(struct drm_device *drm, int pipe)
 {
        struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
+       struct tegra_dc *dc = to_tegra_dc(crtc);
 
        if (!crtc)
                return 0;
 
-       /* TODO: implement real hardware counter using syncpoints */
-       return drm_crtc_vblank_count(crtc);
+       return tegra_dc_get_vblank_counter(dc);
 }
 
 static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe)
@@ -879,8 +883,18 @@ static int tegra_debugfs_framebuffers(struct seq_file *s, void *data)
        return 0;
 }
 
+static int tegra_debugfs_iova(struct seq_file *s, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *)s->private;
+       struct drm_device *drm = node->minor->dev;
+       struct tegra_drm *tegra = drm->dev_private;
+
+       return drm_mm_dump_table(s, &tegra->mm);
+}
+
 static struct drm_info_list tegra_debugfs_list[] = {
        { "framebuffers", tegra_debugfs_framebuffers, 0 },
+       { "iova", tegra_debugfs_iova, 0 },
 };
 
 static int tegra_debugfs_init(struct drm_minor *minor)
index 8cb2dfeaa957380a344a0e0c934d88eebcfa2c46..659b2fcc986dcf1c8ef4abc7364f288b128a3411 100644 (file)
@@ -106,6 +106,7 @@ struct tegra_output;
 
 struct tegra_dc {
        struct host1x_client client;
+       struct host1x_syncpt *syncpt;
        struct device *dev;
        spinlock_t lock;
 
@@ -180,12 +181,11 @@ struct tegra_dc_window {
 };
 
 /* from dc.c */
+u32 tegra_dc_get_vblank_counter(struct tegra_dc *dc);
 void tegra_dc_enable_vblank(struct tegra_dc *dc);
 void tegra_dc_disable_vblank(struct tegra_dc *dc);
 void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file);
 void tegra_dc_commit(struct tegra_dc *dc);
-int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent,
-                        unsigned long pclk, unsigned int div);
 int tegra_dc_state_setup_clock(struct tegra_dc *dc,
                               struct drm_crtc_state *crtc_state,
                               struct clk *clk, unsigned long pclk,
index 7eaaee74a039f36c180629b2233f8455d88b1b6a..06ab1783bba11e7b1299e3d950accf1547e20285 100644 (file)
@@ -952,7 +952,7 @@ static void tegra_hdmi_encoder_mode_set(struct drm_encoder *encoder,
        }
 
        tegra_hdmi_writel(hdmi,
-                         SOR_SEQ_CTL_PU_PC(0) |
+                         SOR_SEQ_PU_PC(0) |
                          SOR_SEQ_PU_PC_ALT(0) |
                          SOR_SEQ_PD_PC(8) |
                          SOR_SEQ_PD_PC_ALT(8),
@@ -1394,8 +1394,8 @@ static int tegra_hdmi_exit(struct host1x_client *client)
 
        tegra_output_exit(&hdmi->output);
 
-       clk_disable_unprepare(hdmi->clk);
        reset_control_assert(hdmi->rst);
+       clk_disable_unprepare(hdmi->clk);
 
        regulator_disable(hdmi->vdd);
        regulator_disable(hdmi->pll);
index 919a19df4e1b59257b3969887fc288c11e43e1d1..a882514389cd05a35e503c8b0adb2bb39ba91ae4 100644 (file)
 #define HDMI_NV_PDISP_SOR_CRCB                                 0x5d
 #define HDMI_NV_PDISP_SOR_BLANK                                        0x5e
 #define HDMI_NV_PDISP_SOR_SEQ_CTL                              0x5f
-#define SOR_SEQ_CTL_PU_PC(x) (((x) & 0xf) <<  0)
+#define SOR_SEQ_PU_PC(x)     (((x) & 0xf) <<  0)
 #define SOR_SEQ_PU_PC_ALT(x) (((x) & 0xf) <<  4)
 #define SOR_SEQ_PD_PC(x)     (((x) & 0xf) <<  8)
 #define SOR_SEQ_PD_PC_ALT(x) (((x) & 0xf) << 12)
index 2afe478ded3ba78e215f678f0ecd0ce09f520755..7591d8901f9a24ddd61d035500116c617e4df3f6 100644 (file)
@@ -41,6 +41,8 @@ struct tegra_sor {
        struct mutex lock;
        bool enabled;
 
+       struct drm_info_list *debugfs_files;
+       struct drm_minor *minor;
        struct dentry *debugfs;
 };
 
@@ -68,13 +70,12 @@ static inline struct tegra_sor *to_sor(struct tegra_output *output)
        return container_of(output, struct tegra_sor, output);
 }
 
-static inline unsigned long tegra_sor_readl(struct tegra_sor *sor,
-                                           unsigned long offset)
+static inline u32 tegra_sor_readl(struct tegra_sor *sor, unsigned long offset)
 {
        return readl(sor->regs + (offset << 2));
 }
 
-static inline void tegra_sor_writel(struct tegra_sor *sor, unsigned long value,
+static inline void tegra_sor_writel(struct tegra_sor *sor, u32 value,
                                    unsigned long offset)
 {
        writel(value, sor->regs + (offset << 2));
@@ -83,9 +84,9 @@ static inline void tegra_sor_writel(struct tegra_sor *sor, unsigned long value,
 static int tegra_sor_dp_train_fast(struct tegra_sor *sor,
                                   struct drm_dp_link *link)
 {
-       unsigned long value;
        unsigned int i;
        u8 pattern;
+       u32 value;
        int err;
 
        /* setup lane parameters */
@@ -202,7 +203,7 @@ static void tegra_sor_update(struct tegra_sor *sor)
 
 static int tegra_sor_setup_pwm(struct tegra_sor *sor, unsigned long timeout)
 {
-       unsigned long value;
+       u32 value;
 
        value = tegra_sor_readl(sor, SOR_PWM_DIV);
        value &= ~SOR_PWM_DIV_MASK;
@@ -281,7 +282,7 @@ static int tegra_sor_wakeup(struct tegra_sor *sor)
 
 static int tegra_sor_power_up(struct tegra_sor *sor, unsigned long timeout)
 {
-       unsigned long value;
+       u32 value;
 
        value = tegra_sor_readl(sor, SOR_PWR);
        value |= SOR_PWR_TRIGGER | SOR_PWR_NORMAL_STATE_PU;
@@ -674,38 +675,195 @@ static const struct file_operations tegra_sor_crc_fops = {
        .release = tegra_sor_crc_release,
 };
 
+static int tegra_sor_show_regs(struct seq_file *s, void *data)
+{
+       struct drm_info_node *node = s->private;
+       struct tegra_sor *sor = node->info_ent->data;
+
+#define DUMP_REG(name)                                         \
+       seq_printf(s, "%-38s %#05x %08x\n", #name, name,        \
+                  tegra_sor_readl(sor, name))
+
+       DUMP_REG(SOR_CTXSW);
+       DUMP_REG(SOR_SUPER_STATE_0);
+       DUMP_REG(SOR_SUPER_STATE_1);
+       DUMP_REG(SOR_STATE_0);
+       DUMP_REG(SOR_STATE_1);
+       DUMP_REG(SOR_HEAD_STATE_0(0));
+       DUMP_REG(SOR_HEAD_STATE_0(1));
+       DUMP_REG(SOR_HEAD_STATE_1(0));
+       DUMP_REG(SOR_HEAD_STATE_1(1));
+       DUMP_REG(SOR_HEAD_STATE_2(0));
+       DUMP_REG(SOR_HEAD_STATE_2(1));
+       DUMP_REG(SOR_HEAD_STATE_3(0));
+       DUMP_REG(SOR_HEAD_STATE_3(1));
+       DUMP_REG(SOR_HEAD_STATE_4(0));
+       DUMP_REG(SOR_HEAD_STATE_4(1));
+       DUMP_REG(SOR_HEAD_STATE_5(0));
+       DUMP_REG(SOR_HEAD_STATE_5(1));
+       DUMP_REG(SOR_CRC_CNTRL);
+       DUMP_REG(SOR_DP_DEBUG_MVID);
+       DUMP_REG(SOR_CLK_CNTRL);
+       DUMP_REG(SOR_CAP);
+       DUMP_REG(SOR_PWR);
+       DUMP_REG(SOR_TEST);
+       DUMP_REG(SOR_PLL_0);
+       DUMP_REG(SOR_PLL_1);
+       DUMP_REG(SOR_PLL_2);
+       DUMP_REG(SOR_PLL_3);
+       DUMP_REG(SOR_CSTM);
+       DUMP_REG(SOR_LVDS);
+       DUMP_REG(SOR_CRC_A);
+       DUMP_REG(SOR_CRC_B);
+       DUMP_REG(SOR_BLANK);
+       DUMP_REG(SOR_SEQ_CTL);
+       DUMP_REG(SOR_LANE_SEQ_CTL);
+       DUMP_REG(SOR_SEQ_INST(0));
+       DUMP_REG(SOR_SEQ_INST(1));
+       DUMP_REG(SOR_SEQ_INST(2));
+       DUMP_REG(SOR_SEQ_INST(3));
+       DUMP_REG(SOR_SEQ_INST(4));
+       DUMP_REG(SOR_SEQ_INST(5));
+       DUMP_REG(SOR_SEQ_INST(6));
+       DUMP_REG(SOR_SEQ_INST(7));
+       DUMP_REG(SOR_SEQ_INST(8));
+       DUMP_REG(SOR_SEQ_INST(9));
+       DUMP_REG(SOR_SEQ_INST(10));
+       DUMP_REG(SOR_SEQ_INST(11));
+       DUMP_REG(SOR_SEQ_INST(12));
+       DUMP_REG(SOR_SEQ_INST(13));
+       DUMP_REG(SOR_SEQ_INST(14));
+       DUMP_REG(SOR_SEQ_INST(15));
+       DUMP_REG(SOR_PWM_DIV);
+       DUMP_REG(SOR_PWM_CTL);
+       DUMP_REG(SOR_VCRC_A_0);
+       DUMP_REG(SOR_VCRC_A_1);
+       DUMP_REG(SOR_VCRC_B_0);
+       DUMP_REG(SOR_VCRC_B_1);
+       DUMP_REG(SOR_CCRC_A_0);
+       DUMP_REG(SOR_CCRC_A_1);
+       DUMP_REG(SOR_CCRC_B_0);
+       DUMP_REG(SOR_CCRC_B_1);
+       DUMP_REG(SOR_EDATA_A_0);
+       DUMP_REG(SOR_EDATA_A_1);
+       DUMP_REG(SOR_EDATA_B_0);
+       DUMP_REG(SOR_EDATA_B_1);
+       DUMP_REG(SOR_COUNT_A_0);
+       DUMP_REG(SOR_COUNT_A_1);
+       DUMP_REG(SOR_COUNT_B_0);
+       DUMP_REG(SOR_COUNT_B_1);
+       DUMP_REG(SOR_DEBUG_A_0);
+       DUMP_REG(SOR_DEBUG_A_1);
+       DUMP_REG(SOR_DEBUG_B_0);
+       DUMP_REG(SOR_DEBUG_B_1);
+       DUMP_REG(SOR_TRIG);
+       DUMP_REG(SOR_MSCHECK);
+       DUMP_REG(SOR_XBAR_CTRL);
+       DUMP_REG(SOR_XBAR_POL);
+       DUMP_REG(SOR_DP_LINKCTL_0);
+       DUMP_REG(SOR_DP_LINKCTL_1);
+       DUMP_REG(SOR_LANE_DRIVE_CURRENT_0);
+       DUMP_REG(SOR_LANE_DRIVE_CURRENT_1);
+       DUMP_REG(SOR_LANE4_DRIVE_CURRENT_0);
+       DUMP_REG(SOR_LANE4_DRIVE_CURRENT_1);
+       DUMP_REG(SOR_LANE_PREEMPHASIS_0);
+       DUMP_REG(SOR_LANE_PREEMPHASIS_1);
+       DUMP_REG(SOR_LANE4_PREEMPHASIS_0);
+       DUMP_REG(SOR_LANE4_PREEMPHASIS_1);
+       DUMP_REG(SOR_LANE_POST_CURSOR_0);
+       DUMP_REG(SOR_LANE_POST_CURSOR_1);
+       DUMP_REG(SOR_DP_CONFIG_0);
+       DUMP_REG(SOR_DP_CONFIG_1);
+       DUMP_REG(SOR_DP_MN_0);
+       DUMP_REG(SOR_DP_MN_1);
+       DUMP_REG(SOR_DP_PADCTL_0);
+       DUMP_REG(SOR_DP_PADCTL_1);
+       DUMP_REG(SOR_DP_DEBUG_0);
+       DUMP_REG(SOR_DP_DEBUG_1);
+       DUMP_REG(SOR_DP_SPARE_0);
+       DUMP_REG(SOR_DP_SPARE_1);
+       DUMP_REG(SOR_DP_AUDIO_CTRL);
+       DUMP_REG(SOR_DP_AUDIO_HBLANK_SYMBOLS);
+       DUMP_REG(SOR_DP_AUDIO_VBLANK_SYMBOLS);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_HEADER);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_0);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_1);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_2);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_3);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_4);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_5);
+       DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK_6);
+       DUMP_REG(SOR_DP_TPG);
+       DUMP_REG(SOR_DP_TPG_CONFIG);
+       DUMP_REG(SOR_DP_LQ_CSTM_0);
+       DUMP_REG(SOR_DP_LQ_CSTM_1);
+       DUMP_REG(SOR_DP_LQ_CSTM_2);
+
+#undef DUMP_REG
+
+       return 0;
+}
+
+static const struct drm_info_list debugfs_files[] = {
+       { "regs", tegra_sor_show_regs, 0, NULL },
+};
+
 static int tegra_sor_debugfs_init(struct tegra_sor *sor,
                                  struct drm_minor *minor)
 {
        struct dentry *entry;
+       unsigned int i;
        int err = 0;
 
        sor->debugfs = debugfs_create_dir("sor", minor->debugfs_root);
        if (!sor->debugfs)
                return -ENOMEM;
 
+       sor->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files),
+                                    GFP_KERNEL);
+       if (!sor->debugfs_files) {
+               err = -ENOMEM;
+               goto remove;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(debugfs_files); i++)
+               sor->debugfs_files[i].data = sor;
+
+       err = drm_debugfs_create_files(sor->debugfs_files,
+                                      ARRAY_SIZE(debugfs_files),
+                                      sor->debugfs, minor);
+       if (err < 0)
+               goto free;
+
        entry = debugfs_create_file("crc", 0644, sor->debugfs, sor,
                                    &tegra_sor_crc_fops);
        if (!entry) {
-               dev_err(sor->dev,
-                       "cannot create /sys/kernel/debug/dri/%s/sor/crc\n",
-                       minor->debugfs_root->d_name.name);
                err = -ENOMEM;
-               goto remove;
+               goto free;
        }
 
        return err;
 
+free:
+       kfree(sor->debugfs_files);
+       sor->debugfs_files = NULL;
 remove:
-       debugfs_remove(sor->debugfs);
+       debugfs_remove_recursive(sor->debugfs);
        sor->debugfs = NULL;
        return err;
 }
 
 static void tegra_sor_debugfs_exit(struct tegra_sor *sor)
 {
-       debugfs_remove_recursive(sor->debugfs);
+       drm_debugfs_remove_files(sor->debugfs_files, ARRAY_SIZE(debugfs_files),
+                                sor->minor);
+       sor->minor = NULL;
+
+       kfree(sor->debugfs_files);
        sor->debugfs = NULL;
+
+       debugfs_remove_recursive(sor->debugfs);
+       sor->debugfs_files = NULL;
 }
 
 static void tegra_sor_connector_dpms(struct drm_connector *connector, int mode)
@@ -791,8 +949,8 @@ static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
        struct tegra_sor_config config;
        struct drm_dp_link link;
        struct drm_dp_aux *aux;
-       unsigned long value;
        int err = 0;
+       u32 value;
 
        mutex_lock(&sor->lock);
 
@@ -1354,12 +1512,30 @@ static int tegra_sor_init(struct host1x_client *client)
                }
        }
 
+       /*
+        * XXX: Remove this reset once proper hand-over from firmware to
+        * kernel is possible.
+        */
+       err = reset_control_assert(sor->rst);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to assert SOR reset: %d\n", err);
+               return err;
+       }
+
        err = clk_prepare_enable(sor->clk);
        if (err < 0) {
                dev_err(sor->dev, "failed to enable clock: %d\n", err);
                return err;
        }
 
+       usleep_range(1000, 3000);
+
+       err = reset_control_deassert(sor->rst);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to deassert SOR reset: %d\n", err);
+               return err;
+       }
+
        err = clk_prepare_enable(sor->clk_safe);
        if (err < 0)
                return err;
diff --git a/drivers/gpu/drm/vgem/Makefile b/drivers/gpu/drm/vgem/Makefile
new file mode 100644 (file)
index 0000000..1055cb7
--- /dev/null
@@ -0,0 +1,4 @@
+ccflags-y := -Iinclude/drm
+vgem-y := vgem_drv.o vgem_dma_buf.o
+
+obj-$(CONFIG_DRM_VGEM) += vgem.o
diff --git a/drivers/gpu/drm/vgem/vgem_dma_buf.c b/drivers/gpu/drm/vgem/vgem_dma_buf.c
new file mode 100644 (file)
index 0000000..0254438
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright Â© 2012 Intel Corporation
+ * Copyright Â© 2014 The Chromium OS Authors
+ *
+ * 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 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.
+ *
+ * Authors:
+ *    Ben Widawsky <ben@bwidawsk.net>
+ *
+ */
+
+#include <linux/dma-buf.h>
+#include "vgem_drv.h"
+
+struct sg_table *vgem_gem_prime_get_sg_table(struct drm_gem_object *gobj)
+{
+       struct drm_vgem_gem_object *obj = to_vgem_bo(gobj);
+       BUG_ON(obj->pages == NULL);
+
+       return drm_prime_pages_to_sg(obj->pages, obj->base.size / PAGE_SIZE);
+}
+
+int vgem_gem_prime_pin(struct drm_gem_object *gobj)
+{
+       struct drm_vgem_gem_object *obj = to_vgem_bo(gobj);
+       return vgem_gem_get_pages(obj);
+}
+
+void vgem_gem_prime_unpin(struct drm_gem_object *gobj)
+{
+       struct drm_vgem_gem_object *obj = to_vgem_bo(gobj);
+       vgem_gem_put_pages(obj);
+}
+
+void *vgem_gem_prime_vmap(struct drm_gem_object *gobj)
+{
+       struct drm_vgem_gem_object *obj = to_vgem_bo(gobj);
+       BUG_ON(obj->pages == NULL);
+
+       return vmap(obj->pages, obj->base.size / PAGE_SIZE, 0, PAGE_KERNEL);
+}
+
+void vgem_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+       vunmap(vaddr);
+}
+
+struct drm_gem_object *vgem_gem_prime_import(struct drm_device *dev,
+                                            struct dma_buf *dma_buf)
+{
+       struct drm_vgem_gem_object *obj = NULL;
+       int ret;
+
+       obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+       if (obj == NULL) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       ret = drm_gem_object_init(dev, &obj->base, dma_buf->size);
+       if (ret) {
+               ret = -ENOMEM;
+               goto fail_free;
+       }
+
+       get_dma_buf(dma_buf);
+
+       obj->base.dma_buf = dma_buf;
+       obj->use_dma_buf = true;
+
+       return &obj->base;
+
+fail_free:
+       kfree(obj);
+fail:
+       return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c
new file mode 100644 (file)
index 0000000..cb3b435
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * Copyright 2011 Red Hat, Inc.
+ * Copyright Â© 2014 The Chromium OS Authors
+ *
+ * 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
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * them 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 MERCHANTIBILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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:
+ *     Adam Jackson <ajax@redhat.com>
+ *     Ben Widawsky <ben@bwidawsk.net>
+ */
+
+/**
+ * This is vgem, a (non-hardware-backed) GEM service.  This is used by Mesa's
+ * software renderer and the X server for efficient buffer sharing.
+ */
+
+#include <linux/module.h>
+#include <linux/ramfs.h>
+#include <linux/shmem_fs.h>
+#include <linux/dma-buf.h>
+#include "vgem_drv.h"
+
+#define DRIVER_NAME    "vgem"
+#define DRIVER_DESC    "Virtual GEM provider"
+#define DRIVER_DATE    "20120112"
+#define DRIVER_MAJOR   1
+#define DRIVER_MINOR   0
+
+void vgem_gem_put_pages(struct drm_vgem_gem_object *obj)
+{
+       drm_gem_put_pages(&obj->base, obj->pages, false, false);
+       obj->pages = NULL;
+}
+
+static void vgem_gem_free_object(struct drm_gem_object *obj)
+{
+       struct drm_vgem_gem_object *vgem_obj = to_vgem_bo(obj);
+
+       drm_gem_free_mmap_offset(obj);
+
+       if (vgem_obj->use_dma_buf && obj->dma_buf) {
+               dma_buf_put(obj->dma_buf);
+               obj->dma_buf = NULL;
+       }
+
+       drm_gem_object_release(obj);
+
+       if (vgem_obj->pages)
+               vgem_gem_put_pages(vgem_obj);
+
+       vgem_obj->pages = NULL;
+
+       kfree(vgem_obj);
+}
+
+int vgem_gem_get_pages(struct drm_vgem_gem_object *obj)
+{
+       struct page **pages;
+
+       if (obj->pages || obj->use_dma_buf)
+               return 0;
+
+       pages = drm_gem_get_pages(&obj->base);
+       if (IS_ERR(pages)) {
+               return PTR_ERR(pages);
+       }
+
+       obj->pages = pages;
+
+       return 0;
+}
+
+static int vgem_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       struct drm_vgem_gem_object *obj = vma->vm_private_data;
+       struct drm_device *dev = obj->base.dev;
+       loff_t num_pages;
+       pgoff_t page_offset;
+       int ret;
+
+       /* We don't use vmf->pgoff since that has the fake offset */
+       page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >>
+               PAGE_SHIFT;
+
+       num_pages = DIV_ROUND_UP(obj->base.size, PAGE_SIZE);
+
+       if (page_offset > num_pages)
+               return VM_FAULT_SIGBUS;
+
+       mutex_lock(&dev->struct_mutex);
+
+       ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address,
+                            obj->pages[page_offset]);
+
+       mutex_unlock(&dev->struct_mutex);
+       switch (ret) {
+       case 0:
+               return VM_FAULT_NOPAGE;
+       case -ENOMEM:
+               return VM_FAULT_OOM;
+       case -EBUSY:
+               return VM_FAULT_RETRY;
+       case -EFAULT:
+       case -EINVAL:
+               return VM_FAULT_SIGBUS;
+       default:
+               WARN_ON(1);
+               return VM_FAULT_SIGBUS;
+       }
+}
+
+static struct vm_operations_struct vgem_gem_vm_ops = {
+       .fault = vgem_gem_fault,
+       .open = drm_gem_vm_open,
+       .close = drm_gem_vm_close,
+};
+
+/* ioctls */
+
+static struct drm_gem_object *vgem_gem_create(struct drm_device *dev,
+                                             struct drm_file *file,
+                                             unsigned int *handle,
+                                             unsigned long size)
+{
+       struct drm_vgem_gem_object *obj;
+       struct drm_gem_object *gem_object;
+       int err;
+
+       size = roundup(size, PAGE_SIZE);
+
+       obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+       if (!obj)
+               return ERR_PTR(-ENOMEM);
+
+       gem_object = &obj->base;
+
+       err = drm_gem_object_init(dev, gem_object, size);
+       if (err)
+               goto out;
+
+       err = drm_gem_handle_create(file, gem_object, handle);
+       if (err)
+               goto handle_out;
+
+       drm_gem_object_unreference_unlocked(gem_object);
+
+       return gem_object;
+
+handle_out:
+       drm_gem_object_release(gem_object);
+out:
+       kfree(obj);
+       return ERR_PTR(err);
+}
+
+static int vgem_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
+                               struct drm_mode_create_dumb *args)
+{
+       struct drm_gem_object *gem_object;
+       uint64_t size;
+       uint64_t pitch = args->width * DIV_ROUND_UP(args->bpp, 8);
+
+       size = args->height * pitch;
+       if (size == 0)
+               return -EINVAL;
+
+       gem_object = vgem_gem_create(dev, file, &args->handle, size);
+
+       if (IS_ERR(gem_object)) {
+               DRM_DEBUG_DRIVER("object creation failed\n");
+               return PTR_ERR(gem_object);
+       }
+
+       args->size = gem_object->size;
+       args->pitch = pitch;
+
+       DRM_DEBUG_DRIVER("Created object of size %lld\n", size);
+
+       return 0;
+}
+
+int vgem_gem_dumb_map(struct drm_file *file, struct drm_device *dev,
+                     uint32_t handle, uint64_t *offset)
+{
+       int ret = 0;
+       struct drm_gem_object *obj;
+
+       mutex_lock(&dev->struct_mutex);
+       obj = drm_gem_object_lookup(dev, file, handle);
+       if (!obj) {
+               ret = -ENOENT;
+               goto unlock;
+       }
+
+       if (!drm_vma_node_has_offset(&obj->vma_node)) {
+               ret = drm_gem_create_mmap_offset(obj);
+               if (ret)
+                       goto unref;
+       }
+
+       BUG_ON(!obj->filp);
+
+       obj->filp->private_data = obj;
+
+       ret = vgem_gem_get_pages(to_vgem_bo(obj));
+       if (ret)
+               goto fail_get_pages;
+
+       *offset = drm_vma_node_offset_addr(&obj->vma_node);
+
+       goto unref;
+
+fail_get_pages:
+       drm_gem_free_mmap_offset(obj);
+unref:
+       drm_gem_object_unreference(obj);
+unlock:
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+}
+
+int vgem_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct drm_file *priv = filp->private_data;
+       struct drm_device *dev = priv->minor->dev;
+       struct drm_vma_offset_node *node;
+       struct drm_gem_object *obj;
+       struct drm_vgem_gem_object *vgem_obj;
+       int ret = 0;
+
+       mutex_lock(&dev->struct_mutex);
+
+       node = drm_vma_offset_exact_lookup(dev->vma_offset_manager,
+                                          vma->vm_pgoff,
+                                          vma_pages(vma));
+       if (!node) {
+               ret = -EINVAL;
+               goto out_unlock;
+       } else if (!drm_vma_node_is_allowed(node, filp)) {
+               ret = -EACCES;
+               goto out_unlock;
+       }
+
+       obj = container_of(node, struct drm_gem_object, vma_node);
+
+       vgem_obj = to_vgem_bo(obj);
+
+       if (obj->dma_buf && vgem_obj->use_dma_buf) {
+               ret = dma_buf_mmap(obj->dma_buf, vma, 0);
+               goto out_unlock;
+       }
+
+       if (!obj->dev->driver->gem_vm_ops) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP;
+       vma->vm_ops = obj->dev->driver->gem_vm_ops;
+       vma->vm_private_data = vgem_obj;
+       vma->vm_page_prot =
+               pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+
+       mutex_unlock(&dev->struct_mutex);
+       drm_gem_vm_open(vma);
+       return ret;
+
+out_unlock:
+       mutex_unlock(&dev->struct_mutex);
+
+       return ret;
+}
+
+
+static struct drm_ioctl_desc vgem_ioctls[] = {
+};
+
+static const struct file_operations vgem_driver_fops = {
+       .owner          = THIS_MODULE,
+       .open           = drm_open,
+       .mmap           = vgem_drm_gem_mmap,
+       .poll           = drm_poll,
+       .read           = drm_read,
+       .unlocked_ioctl = drm_ioctl,
+       .release        = drm_release,
+};
+
+static struct drm_driver vgem_driver = {
+       .driver_features                = DRIVER_GEM | DRIVER_PRIME,
+       .gem_free_object                = vgem_gem_free_object,
+       .gem_vm_ops                     = &vgem_gem_vm_ops,
+       .ioctls                         = vgem_ioctls,
+       .fops                           = &vgem_driver_fops,
+       .dumb_create                    = vgem_gem_dumb_create,
+       .dumb_map_offset                = vgem_gem_dumb_map,
+       .prime_handle_to_fd             = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle             = drm_gem_prime_fd_to_handle,
+       .gem_prime_export               = drm_gem_prime_export,
+       .gem_prime_import               = vgem_gem_prime_import,
+       .gem_prime_pin                  = vgem_gem_prime_pin,
+       .gem_prime_unpin                = vgem_gem_prime_unpin,
+       .gem_prime_get_sg_table         = vgem_gem_prime_get_sg_table,
+       .gem_prime_vmap                 = vgem_gem_prime_vmap,
+       .gem_prime_vunmap               = vgem_gem_prime_vunmap,
+       .name   = DRIVER_NAME,
+       .desc   = DRIVER_DESC,
+       .date   = DRIVER_DATE,
+       .major  = DRIVER_MAJOR,
+       .minor  = DRIVER_MINOR,
+};
+
+struct drm_device *vgem_device;
+
+static int __init vgem_init(void)
+{
+       int ret;
+
+       vgem_device = drm_dev_alloc(&vgem_driver, NULL);
+       if (!vgem_device) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret  = drm_dev_register(vgem_device, 0);
+
+       if (ret)
+               goto out_unref;
+
+       return 0;
+
+out_unref:
+       drm_dev_unref(vgem_device);
+out:
+       return ret;
+}
+
+static void __exit vgem_exit(void)
+{
+       drm_dev_unregister(vgem_device);
+       drm_dev_unref(vgem_device);
+}
+
+module_init(vgem_init);
+module_exit(vgem_exit);
+
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/vgem/vgem_drv.h b/drivers/gpu/drm/vgem/vgem_drv.h
new file mode 100644 (file)
index 0000000..57ab4d8
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright Â© 2012 Intel Corporation
+ * Copyright Â© 2014 The Chromium OS Authors
+ *
+ * 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 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.
+ *
+ * Authors:
+ *    Ben Widawsky <ben@bwidawsk.net>
+ *
+ */
+
+#ifndef _VGEM_DRV_H_
+#define _VGEM_DRV_H_
+
+#include <drm/drmP.h>
+#include <drm/drm_gem.h>
+
+#define to_vgem_bo(x) container_of(x, struct drm_vgem_gem_object, base)
+struct drm_vgem_gem_object {
+       struct drm_gem_object base;
+       struct page **pages;
+       bool use_dma_buf;
+};
+
+/* vgem_drv.c */
+extern void vgem_gem_put_pages(struct drm_vgem_gem_object *obj);
+extern int vgem_gem_get_pages(struct drm_vgem_gem_object *obj);
+
+/* vgem_dma_buf.c */
+extern struct sg_table *vgem_gem_prime_get_sg_table(
+                       struct drm_gem_object *gobj);
+extern int vgem_gem_prime_pin(struct drm_gem_object *gobj);
+extern void vgem_gem_prime_unpin(struct drm_gem_object *gobj);
+extern void *vgem_gem_prime_vmap(struct drm_gem_object *gobj);
+extern void vgem_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
+extern struct drm_gem_object *vgem_gem_prime_import(struct drm_device *dev,
+                                                   struct dma_buf *dma_buf);
+
+
+#endif
index e13b9cbc304e9d17a0d5ff55179b2d8b7f93ca7b..620bb5cf617c9689a9113e989d585346f420de3d 100644 (file)
  */
 
 #define VMW_IOCTL_DEF(ioctl, func, flags) \
-  [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {DRM_##ioctl, flags, func, DRM_IOCTL_##ioctl}
+  [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {DRM_IOCTL_##ioctl, flags, func}
 
 /**
  * Ioctl definitions.
@@ -1044,7 +1044,7 @@ static long vmw_generic_ioctl(struct file *filp, unsigned int cmd,
                const struct drm_ioctl_desc *ioctl =
                        &vmw_ioctls[nr - DRM_COMMAND_BASE];
 
-               if (unlikely(ioctl->cmd_drv != cmd)) {
+               if (unlikely(ioctl->cmd != cmd)) {
                        DRM_ERROR("Invalid command format, ioctl %d\n",
                                  nr - DRM_COMMAND_BASE);
                        return -EINVAL;
index b10550ee1d8958366b208f3e1927426663e8b91f..6b7fdc1e2ed078c337c8fa235633fcc105c4ccde 100644 (file)
@@ -425,6 +425,12 @@ u32 host1x_syncpt_read_min(struct host1x_syncpt *sp)
 }
 EXPORT_SYMBOL(host1x_syncpt_read_min);
 
+u32 host1x_syncpt_read(struct host1x_syncpt *sp)
+{
+       return host1x_syncpt_load(sp);
+}
+EXPORT_SYMBOL(host1x_syncpt_read);
+
 int host1x_syncpt_nb_pts(struct host1x *host)
 {
        return host->info->nb_pts;
index 4864f830079779a5e332f7872c8745795aea5766..9ef2e1f54ca47c2611008d872ab8dda0e1c7df5a 100644 (file)
@@ -147,20 +147,20 @@ static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand,
        writel(reg2, priv->dc_tmpl_reg + word * 8 + 4);
 }
 
-static int ipu_pixfmt_to_map(u32 fmt)
+static int ipu_bus_format_to_map(u32 fmt)
 {
        switch (fmt) {
-       case V4L2_PIX_FMT_RGB24:
+       case MEDIA_BUS_FMT_RGB888_1X24:
                return IPU_DC_MAP_RGB24;
-       case V4L2_PIX_FMT_RGB565:
+       case MEDIA_BUS_FMT_RGB565_1X16:
                return IPU_DC_MAP_RGB565;
-       case IPU_PIX_FMT_GBR24:
+       case MEDIA_BUS_FMT_GBR888_1X24:
                return IPU_DC_MAP_GBR24;
-       case V4L2_PIX_FMT_BGR666:
+       case MEDIA_BUS_FMT_RGB666_1X18:
                return IPU_DC_MAP_BGR666;
-       case v4l2_fourcc('L', 'V', 'D', '6'):
+       case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
                return IPU_DC_MAP_LVDS666;
-       case V4L2_PIX_FMT_BGR24:
+       case MEDIA_BUS_FMT_BGR888_1X24:
                return IPU_DC_MAP_BGR24;
        default:
                return -EINVAL;
@@ -168,7 +168,7 @@ static int ipu_pixfmt_to_map(u32 fmt)
 }
 
 int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
-               u32 pixel_fmt, u32 width)
+               u32 bus_format, u32 width)
 {
        struct ipu_dc_priv *priv = dc->priv;
        u32 reg = 0;
@@ -176,7 +176,7 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
 
        dc->di = ipu_di_get_num(di);
 
-       map = ipu_pixfmt_to_map(pixel_fmt);
+       map = ipu_bus_format_to_map(bus_format);
        if (map < 0) {
                dev_dbg(priv->dev, "IPU_DISP: No MAP\n");
                return map;
index 3ddfb3d0b64d266cb95345ccb68c1a991521cc1d..2970c6bb668ca9766eb93098adf442042e7c5f8f 100644 (file)
@@ -441,8 +441,7 @@ static void ipu_di_config_clock(struct ipu_di *di,
 
                        in_rate = clk_get_rate(clk);
                        div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
-                       if (div == 0)
-                               div = 1;
+                       div = clamp(div, 1U, 255U);
 
                        clkgen0 = div << 4;
                }
@@ -459,8 +458,7 @@ static void ipu_di_config_clock(struct ipu_di *di,
 
                clkrate = clk_get_rate(di->clk_ipu);
                div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
-               if (div == 0)
-                       div = 1;
+               div = clamp(div, 1U, 255U);
                rate = clkrate / div;
 
                error = rate / (sig->mode.pixelclock / 1000);
@@ -483,8 +481,7 @@ static void ipu_di_config_clock(struct ipu_di *di,
 
                        in_rate = clk_get_rate(clk);
                        div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
-                       if (div == 0)
-                               div = 1;
+                       div = clamp(div, 1U, 255U);
 
                        clkgen0 = div << 4;
                }
index ad75588e162988ff64c11aea6287868e0606d8cb..1dcb96ccda660f17a2f6fdd436d6474a115ac156 100644 (file)
@@ -297,8 +297,8 @@ static int calc_resize_coeffs(struct ipu_ic *ic,
                return -EINVAL;
        }
 
-       /* Cannot downsize more than 8:1 */
-       if ((out_size << 3) < in_size) {
+       /* Cannot downsize more than 4:1 */
+       if ((out_size << 2) < in_size) {
                dev_err(ipu->dev, "Unsupported downsize\n");
                return -EINVAL;
        }
index 1096da327130526080139e628fdd0a0130d32861..75c6d2103e07adad3b11919687e81f8dd7a8fca3 100644 (file)
@@ -659,7 +659,7 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p)
 
        mutex_lock(&data->mutex);
 
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = bma180_get_data_reg(data, bit);
                if (ret < 0) {
index 066d0c04072c69943fa21313fb47f06c72fedcea..75567fd457dcc4b9bd7c147fdc4cb229cdbaf0c4 100644 (file)
@@ -168,14 +168,14 @@ static const struct {
        int val;
        int val2;
        u8 bw_bits;
-} bmc150_accel_samp_freq_table[] = { {7, 810000, 0x08},
-                                    {15, 630000, 0x09},
-                                    {31, 250000, 0x0A},
-                                    {62, 500000, 0x0B},
-                                    {125, 0, 0x0C},
-                                    {250, 0, 0x0D},
-                                    {500, 0, 0x0E},
-                                    {1000, 0, 0x0F} };
+} bmc150_accel_samp_freq_table[] = { {15, 620000, 0x08},
+                                    {31, 260000, 0x09},
+                                    {62, 500000, 0x0A},
+                                    {125, 0, 0x0B},
+                                    {250, 0, 0x0C},
+                                    {500, 0, 0x0D},
+                                    {1000, 0, 0x0E},
+                                    {2000, 0, 0x0F} };
 
 static const struct {
        int bw_bits;
@@ -840,7 +840,7 @@ static int bmc150_accel_validate_trigger(struct iio_dev *indio_dev,
 }
 
 static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
-               "7.810000 15.630000 31.250000 62.500000 125 250 500 1000");
+               "15.620000 31.260000 62.50000 125 250 500 1000 2000");
 
 static struct attribute *bmc150_accel_attributes[] = {
        &iio_const_attr_sampling_frequency_available.dev_attr.attr,
@@ -986,7 +986,7 @@ static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
        int bit, ret, i = 0;
 
        mutex_lock(&data->mutex);
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = i2c_smbus_read_word_data(data->client,
                                               BMC150_ACCEL_AXIS_TO_REG(bit));
index 567de269cc00650191541a98ac8d5818d0ea8661..1a6379525fa47e73497b17866be4276fc88c8065 100644 (file)
@@ -956,7 +956,7 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p)
 
        mutex_lock(&data->mutex);
 
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = kxcjk1013_get_acc_reg(data, bit);
                if (ret < 0) {
index 202daf889be276315d24575b1301349f295fe4c8..46379b1fb25b59b10018a121b2cc8dc78082d4a6 100644 (file)
@@ -137,7 +137,8 @@ config AXP288_ADC
 
 config CC10001_ADC
        tristate "Cosmic Circuits 10001 ADC driver"
-       depends on HAS_IOMEM || HAVE_CLK || REGULATOR
+       depends on HAVE_CLK || REGULATOR
+       depends on HAS_IOMEM
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        help
index ff61ae55dd3ff8ac73c0925c0b88fa6a75a1083d..8a0eb4a04fb55b9cb2436db5b16f678f654b8a26 100644 (file)
@@ -544,7 +544,6 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
 {
        struct iio_dev *idev = iio_trigger_get_drvdata(trig);
        struct at91_adc_state *st = iio_priv(idev);
-       struct iio_buffer *buffer = idev->buffer;
        struct at91_adc_reg_desc *reg = st->registers;
        u32 status = at91_adc_readl(st, reg->trigger_register);
        int value;
@@ -564,7 +563,7 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
                at91_adc_writel(st, reg->trigger_register,
                                status | value);
 
-               for_each_set_bit(bit, buffer->scan_mask,
+               for_each_set_bit(bit, idev->active_scan_mask,
                                 st->num_channels) {
                        struct iio_chan_spec const *chan = idev->channels + bit;
                        at91_adc_writel(st, AT91_ADC_CHER,
@@ -579,7 +578,7 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
                at91_adc_writel(st, reg->trigger_register,
                                status & ~value);
 
-               for_each_set_bit(bit, buffer->scan_mask,
+               for_each_set_bit(bit, idev->active_scan_mask,
                                 st->num_channels) {
                        struct iio_chan_spec const *chan = idev->channels + bit;
                        at91_adc_writel(st, AT91_ADC_CHDR,
index 2e5cc4409f78884e82f309c729febabe3ff7f982..a0e7161f040c91daca74a469d27ff641be9ea915 100644 (file)
@@ -188,12 +188,11 @@ static int tiadc_buffer_preenable(struct iio_dev *indio_dev)
 static int tiadc_buffer_postenable(struct iio_dev *indio_dev)
 {
        struct tiadc_device *adc_dev = iio_priv(indio_dev);
-       struct iio_buffer *buffer = indio_dev->buffer;
        unsigned int enb = 0;
        u8 bit;
 
        tiadc_step_config(indio_dev);
-       for_each_set_bit(bit, buffer->scan_mask, adc_dev->channels)
+       for_each_set_bit(bit, indio_dev->active_scan_mask, adc_dev->channels)
                enb |= (get_adc_step_bit(adc_dev, bit) << 1);
        adc_dev->buffer_en_ch_steps = enb;
 
index 8ec353c01d98e02e7074df9d4d295ec19f772f09..e63b8e76d4c3d54edc25d23561f28a11afeb05e7 100644 (file)
@@ -141,9 +141,13 @@ struct vf610_adc {
        struct regulator *vref;
        struct vf610_adc_feature adc_feature;
 
+       u32 sample_freq_avail[5];
+
        struct completion completion;
 };
 
+static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
+
 #define VF610_ADC_CHAN(_idx, _chan_type) {                     \
        .type = (_chan_type),                                   \
        .indexed = 1,                                           \
@@ -180,35 +184,47 @@ static const struct iio_chan_spec vf610_adc_iio_channels[] = {
        /* sentinel */
 };
 
-/*
- * ADC sample frequency, unit is ADCK cycles.
- * ADC clk source is ipg clock, which is the same as bus clock.
- *
- * ADC conversion time = SFCAdder + AverageNum x (BCT + LSTAdder)
- * SFCAdder: fixed to 6 ADCK cycles
- * AverageNum: 1, 4, 8, 16, 32 samples for hardware average.
- * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
- * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles
- *
- * By default, enable 12 bit resolution mode, clock source
- * set to ipg clock, So get below frequency group:
- */
-static const u32 vf610_sample_freq_avail[5] =
-{1941176, 559332, 286957, 145374, 73171};
+static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
+{
+       unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk);
+       int i;
+
+       /*
+        * Calculate ADC sample frequencies
+        * Sample time unit is ADCK cycles. ADCK clk source is ipg clock,
+        * which is the same as bus clock.
+        *
+        * ADC conversion time = SFCAdder + AverageNum x (BCT + LSTAdder)
+        * SFCAdder: fixed to 6 ADCK cycles
+        * AverageNum: 1, 4, 8, 16, 32 samples for hardware average.
+        * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
+        * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles
+        */
+       adck_rate = ipg_rate / info->adc_feature.clk_div;
+       for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++)
+               info->sample_freq_avail[i] =
+                       adck_rate / (6 + vf610_hw_avgs[i] * (25 + 3));
+}
 
 static inline void vf610_adc_cfg_init(struct vf610_adc *info)
 {
+       struct vf610_adc_feature *adc_feature = &info->adc_feature;
+
        /* set default Configuration for ADC controller */
-       info->adc_feature.clk_sel = VF610_ADCIOC_BUSCLK_SET;
-       info->adc_feature.vol_ref = VF610_ADCIOC_VR_VREF_SET;
+       adc_feature->clk_sel = VF610_ADCIOC_BUSCLK_SET;
+       adc_feature->vol_ref = VF610_ADCIOC_VR_VREF_SET;
+
+       adc_feature->calibration = true;
+       adc_feature->ovwren = true;
+
+       adc_feature->res_mode = 12;
+       adc_feature->sample_rate = 1;
+       adc_feature->lpm = true;
 
-       info->adc_feature.calibration = true;
-       info->adc_feature.ovwren = true;
+       /* Use a save ADCK which is below 20MHz on all devices */
+       adc_feature->clk_div = 8;
 
-       info->adc_feature.clk_div = 1;
-       info->adc_feature.res_mode = 12;
-       info->adc_feature.sample_rate = 1;
-       info->adc_feature.lpm = true;
+       vf610_adc_calculate_rates(info);
 }
 
 static void vf610_adc_cfg_post_set(struct vf610_adc *info)
@@ -290,12 +306,10 @@ static void vf610_adc_cfg_set(struct vf610_adc *info)
 
        cfg_data = readl(info->regs + VF610_REG_ADC_CFG);
 
-       /* low power configuration */
        cfg_data &= ~VF610_ADC_ADLPC_EN;
        if (adc_feature->lpm)
                cfg_data |= VF610_ADC_ADLPC_EN;
 
-       /* disable high speed */
        cfg_data &= ~VF610_ADC_ADHSC_EN;
 
        writel(cfg_data, info->regs + VF610_REG_ADC_CFG);
@@ -435,10 +449,27 @@ static irqreturn_t vf610_adc_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("1941176, 559332, 286957, 145374, 73171");
+static ssize_t vf610_show_samp_freq_avail(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct vf610_adc *info = iio_priv(dev_to_iio_dev(dev));
+       size_t len = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(info->sample_freq_avail); i++)
+               len += scnprintf(buf + len, PAGE_SIZE - len,
+                       "%u ", info->sample_freq_avail[i]);
+
+       /* replace trailing space by newline */
+       buf[len - 1] = '\n';
+
+       return len;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(vf610_show_samp_freq_avail);
 
 static struct attribute *vf610_attributes[] = {
-       &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+       &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
        NULL
 };
 
@@ -502,7 +533,7 @@ static int vf610_read_raw(struct iio_dev *indio_dev,
                return IIO_VAL_FRACTIONAL_LOG2;
 
        case IIO_CHAN_INFO_SAMP_FREQ:
-               *val = vf610_sample_freq_avail[info->adc_feature.sample_rate];
+               *val = info->sample_freq_avail[info->adc_feature.sample_rate];
                *val2 = 0;
                return IIO_VAL_INT;
 
@@ -525,9 +556,9 @@ static int vf610_write_raw(struct iio_dev *indio_dev,
        switch (mask) {
                case IIO_CHAN_INFO_SAMP_FREQ:
                        for (i = 0;
-                               i < ARRAY_SIZE(vf610_sample_freq_avail);
+                               i < ARRAY_SIZE(info->sample_freq_avail);
                                i++)
-                               if (val == vf610_sample_freq_avail[i]) {
+                               if (val == info->sample_freq_avail[i]) {
                                        info->adc_feature.sample_rate = i;
                                        vf610_adc_sample_set(info);
                                        return 0;
index 60451b32824212a039b8ac9358751faa1af12819..ccf3ea7e1afa8ca1848937b9a8b92e1f2cefc8be 100644 (file)
@@ -822,7 +822,7 @@ static irqreturn_t bmg160_trigger_handler(int irq, void *p)
        int bit, ret, i = 0;
 
        mutex_lock(&data->mutex);
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = i2c_smbus_read_word_data(data->client,
                                               BMG160_AXIS_TO_REG(bit));
index e0017c22bb9c6ce3b4f4f9c753a8ce1364621b19..f53e9a803a0e1ec1589a5b0ad25d7aa1f8d54e70 100644 (file)
@@ -60,7 +60,7 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
        iio_trigger_set_drvdata(adis->trig, adis);
        ret = iio_trigger_register(adis->trig);
 
-       indio_dev->trig = adis->trig;
+       indio_dev->trig = iio_trigger_get(adis->trig);
        if (ret)
                goto error_free_irq;
 
index d8d5bed65e072cae577968edb78e2e592c2a5bfa..ef76afe2643cb0bebe512124ca8c9326e09229c2 100644 (file)
@@ -410,42 +410,46 @@ error_read_raw:
        }
 }
 
-static int inv_mpu6050_write_fsr(struct inv_mpu6050_state *st, int fsr)
+static int inv_mpu6050_write_gyro_scale(struct inv_mpu6050_state *st, int val)
 {
-       int result;
+       int result, i;
        u8 d;
 
-       if (fsr < 0 || fsr > INV_MPU6050_MAX_GYRO_FS_PARAM)
-               return -EINVAL;
-       if (fsr == st->chip_config.fsr)
-               return 0;
+       for (i = 0; i < ARRAY_SIZE(gyro_scale_6050); ++i) {
+               if (gyro_scale_6050[i] == val) {
+                       d = (i << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT);
+                       result = inv_mpu6050_write_reg(st,
+                                       st->reg->gyro_config, d);
+                       if (result)
+                               return result;
 
-       d = (fsr << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT);
-       result = inv_mpu6050_write_reg(st, st->reg->gyro_config, d);
-       if (result)
-               return result;
-       st->chip_config.fsr = fsr;
+                       st->chip_config.fsr = i;
+                       return 0;
+               }
+       }
 
-       return 0;
+       return -EINVAL;
 }
 
-static int inv_mpu6050_write_accel_fs(struct inv_mpu6050_state *st, int fs)
+static int inv_mpu6050_write_accel_scale(struct inv_mpu6050_state *st, int val)
 {
-       int result;
+       int result, i;
        u8 d;
 
-       if (fs < 0 || fs > INV_MPU6050_MAX_ACCL_FS_PARAM)
-               return -EINVAL;
-       if (fs == st->chip_config.accl_fs)
-               return 0;
+       for (i = 0; i < ARRAY_SIZE(accel_scale); ++i) {
+               if (accel_scale[i] == val) {
+                       d = (i << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT);
+                       result = inv_mpu6050_write_reg(st,
+                                       st->reg->accl_config, d);
+                       if (result)
+                               return result;
 
-       d = (fs << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT);
-       result = inv_mpu6050_write_reg(st, st->reg->accl_config, d);
-       if (result)
-               return result;
-       st->chip_config.accl_fs = fs;
+                       st->chip_config.accl_fs = i;
+                       return 0;
+               }
+       }
 
-       return 0;
+       return -EINVAL;
 }
 
 static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
@@ -471,10 +475,10 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
        case IIO_CHAN_INFO_SCALE:
                switch (chan->type) {
                case IIO_ANGL_VEL:
-                       result = inv_mpu6050_write_fsr(st, val);
+                       result = inv_mpu6050_write_gyro_scale(st, val2);
                        break;
                case IIO_ACCEL:
-                       result = inv_mpu6050_write_accel_fs(st, val);
+                       result = inv_mpu6050_write_accel_scale(st, val2);
                        break;
                default:
                        result = -EINVAL;
index 0cd306a72a6e347391ea97d7a02d05e54b6c64ab..ba27e277511fc52585f8fa25fd20d49bca61be96 100644 (file)
 #include <linux/poll.h>
 #include "inv_mpu_iio.h"
 
+static void inv_clear_kfifo(struct inv_mpu6050_state *st)
+{
+       unsigned long flags;
+
+       /* take the spin lock sem to avoid interrupt kick in */
+       spin_lock_irqsave(&st->time_stamp_lock, flags);
+       kfifo_reset(&st->timestamps);
+       spin_unlock_irqrestore(&st->time_stamp_lock, flags);
+}
+
 int inv_reset_fifo(struct iio_dev *indio_dev)
 {
        int result;
@@ -50,6 +60,10 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
                                        INV_MPU6050_BIT_FIFO_RST);
        if (result)
                goto reset_fifo_fail;
+
+       /* clear timestamps fifo */
+       inv_clear_kfifo(st);
+
        /* enable interrupt */
        if (st->chip_config.accl_fifo_enable ||
            st->chip_config.gyro_fifo_enable) {
@@ -83,16 +97,6 @@ reset_fifo_fail:
        return result;
 }
 
-static void inv_clear_kfifo(struct inv_mpu6050_state *st)
-{
-       unsigned long flags;
-
-       /* take the spin lock sem to avoid interrupt kick in */
-       spin_lock_irqsave(&st->time_stamp_lock, flags);
-       kfifo_reset(&st->timestamps);
-       spin_unlock_irqrestore(&st->time_stamp_lock, flags);
-}
-
 /**
  * inv_mpu6050_irq_handler() - Cache a timestamp at each data ready interrupt.
  */
@@ -184,7 +188,6 @@ end_session:
 flush_fifo:
        /* Flush HW and SW FIFOs. */
        inv_reset_fifo(indio_dev);
-       inv_clear_kfifo(st);
        mutex_unlock(&indio_dev->mlock);
        iio_trigger_notify_done(indio_dev->trig);
 
index 5cc3692acf377664dbf255a698bb5e64606fe864..b3a36376c719317006cf8b9d30e1369f8b6af8fb 100644 (file)
@@ -1227,7 +1227,7 @@ static irqreturn_t kmx61_trigger_handler(int irq, void *p)
                base = KMX61_MAG_XOUT_L;
 
        mutex_lock(&data->lock);
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = kmx61_read_measurement(data, base, bit);
                if (ret < 0) {
index aaba9d3d980ee623ad6b78111a9c9708198b23e0..4df97f650e448e80053e037fed6d5e208493c687 100644 (file)
@@ -847,8 +847,7 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
  * @attr_list: List of IIO device attributes
  *
  * This function frees the memory allocated for each of the IIO device
- * attributes in the list. Note: if you want to reuse the list after calling
- * this function you have to reinitialize it using INIT_LIST_HEAD().
+ * attributes in the list.
  */
 void iio_free_chan_devattr_list(struct list_head *attr_list)
 {
@@ -856,6 +855,7 @@ void iio_free_chan_devattr_list(struct list_head *attr_list)
 
        list_for_each_entry_safe(p, n, attr_list, l) {
                kfree(p->dev_attr.attr.name);
+               list_del(&p->l);
                kfree(p);
        }
 }
@@ -936,6 +936,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
 
        iio_free_chan_devattr_list(&indio_dev->channel_attr_list);
        kfree(indio_dev->chan_attr_group.attrs);
+       indio_dev->chan_attr_group.attrs = NULL;
 }
 
 static void iio_dev_release(struct device *device)
index a4b397048f71f9fe2e22be46f45fca0fb06cb8ff..a99692ba91bc75fb3186f69f2d55bfc9efd6652c 100644 (file)
@@ -500,6 +500,7 @@ int iio_device_register_eventset(struct iio_dev *indio_dev)
 error_free_setup_event_lines:
        iio_free_chan_devattr_list(&indio_dev->event_interface->dev_attr_list);
        kfree(indio_dev->event_interface);
+       indio_dev->event_interface = NULL;
        return ret;
 }
 
index 74dff4e4a11acdda1ec44ec6eaec75ef4d0543e4..89fca3a7075039b9b9a0de5514c1b96758d4593b 100644 (file)
@@ -494,7 +494,7 @@ static irqreturn_t sx9500_trigger_handler(int irq, void *private)
 
        mutex_lock(&data->mutex);
 
-       for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+       for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
                ret = sx9500_read_proximity(data, &indio_dev->channels[bit],
                                            &val);
index aec7a6aa2951db47bc6b5be969a29d1867688b23..8c014b5dab4c82ff805a744c89655555a56094fc 100644 (file)
@@ -99,6 +99,14 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
        if (dmasync)
                dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs);
 
+       /*
+        * If the combination of the addr and size requested for this memory
+        * region causes an integer overflow, return error.
+        */
+       if ((PAGE_ALIGN(addr + size) <= size) ||
+           (PAGE_ALIGN(addr + size) <= addr))
+               return ERR_PTR(-EINVAL);
+
        if (!can_do_mlock())
                return ERR_PTR(-EPERM);
 
index 1bd15ebc01f2df5002eca38f7089a61701471f5d..27bcdbc950c9fc2df9067504cfe055bf379eee78 100644 (file)
@@ -1154,10 +1154,28 @@ out:
        mutex_unlock(&alps_mutex);
 }
 
-static void alps_report_bare_ps2_packet(struct input_dev *dev,
+static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
                                        unsigned char packet[],
                                        bool report_buttons)
 {
+       struct alps_data *priv = psmouse->private;
+       struct input_dev *dev;
+
+       /* Figure out which device to use to report the bare packet */
+       if (priv->proto_version == ALPS_PROTO_V2 &&
+           (priv->flags & ALPS_DUALPOINT)) {
+               /* On V2 devices the DualPoint Stick reports bare packets */
+               dev = priv->dev2;
+       } else if (unlikely(IS_ERR_OR_NULL(priv->dev3))) {
+               /* Register dev3 mouse if we received PS/2 packet first time */
+               if (!IS_ERR(priv->dev3))
+                       psmouse_queue_work(psmouse, &priv->dev3_register_work,
+                                          0);
+               return;
+       } else {
+               dev = priv->dev3;
+       }
+
        if (report_buttons)
                alps_report_buttons(dev, NULL,
                                packet[0] & 1, packet[0] & 2, packet[0] & 4);
@@ -1232,8 +1250,8 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
                 * de-synchronization.
                 */
 
-               alps_report_bare_ps2_packet(priv->dev2,
-                                           &psmouse->packet[3], false);
+               alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3],
+                                           false);
 
                /*
                 * Continue with the standard ALPS protocol handling,
@@ -1289,18 +1307,9 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
         * properly we only do this if the device is fully synchronized.
         */
        if (!psmouse->out_of_sync_cnt && (psmouse->packet[0] & 0xc8) == 0x08) {
-
-               /* Register dev3 mouse if we received PS/2 packet first time */
-               if (unlikely(!priv->dev3))
-                       psmouse_queue_work(psmouse,
-                                          &priv->dev3_register_work, 0);
-
                if (psmouse->pktcnt == 3) {
-                       /* Once dev3 mouse device is registered report data */
-                       if (likely(!IS_ERR_OR_NULL(priv->dev3)))
-                               alps_report_bare_ps2_packet(priv->dev3,
-                                                           psmouse->packet,
-                                                           true);
+                       alps_report_bare_ps2_packet(psmouse, psmouse->packet,
+                                                   true);
                        return PSMOUSE_FULL_PACKET;
                }
                return PSMOUSE_GOOD_DATA;
@@ -2281,10 +2290,12 @@ static int alps_set_protocol(struct psmouse *psmouse,
                priv->set_abs_params = alps_set_abs_params_mt;
                priv->nibble_commands = alps_v3_nibble_commands;
                priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
-               priv->x_max = 1360;
-               priv->y_max = 660;
                priv->x_bits = 23;
                priv->y_bits = 12;
+
+               if (alps_dolphin_get_device_area(psmouse, priv))
+                       return -EIO;
+
                break;
 
        case ALPS_PROTO_V6:
@@ -2303,9 +2314,8 @@ static int alps_set_protocol(struct psmouse *psmouse,
                priv->set_abs_params = alps_set_abs_params_mt;
                priv->nibble_commands = alps_v3_nibble_commands;
                priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
-
-               if (alps_dolphin_get_device_area(psmouse, priv))
-                       return -EIO;
+               priv->x_max = 0xfff;
+               priv->y_max = 0x7ff;
 
                if (priv->fw_ver[1] != 0xba)
                        priv->flags |= ALPS_BUTTONPAD;
index dda605836546847afbdbdd4c77c976134a914a2e..3b06c8a360b661f02ed3aa826e5a996b93e5b358 100644 (file)
@@ -152,6 +152,11 @@ static const struct min_max_quirk min_max_pnpid_table[] = {
                {ANY_BOARD_ID, ANY_BOARD_ID},
                1024, 5022, 2508, 4832
        },
+       {
+               (const char * const []){"LEN2006", NULL},
+               {2691, 2691},
+               1024, 5045, 2457, 4832
+       },
        {
                (const char * const []){"LEN2006", NULL},
                {ANY_BOARD_ID, ANY_BOARD_ID},
@@ -189,7 +194,7 @@ static const char * const topbuttonpad_pnp_ids[] = {
        "LEN2003",
        "LEN2004", /* L440 */
        "LEN2005",
-       "LEN2006",
+       "LEN2006", /* Edge E440/E540 */
        "LEN2007",
        "LEN2008",
        "LEN2009",
index fc13dd56953e1eb2cb25107ef017336546b733a7..a3adde6519f0a24b7150f8e69ceabed534ceaa38 100644 (file)
@@ -1288,10 +1288,13 @@ static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain,
                return 0;
 
        spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
-       if (smmu_domain->smmu->features & ARM_SMMU_FEAT_TRANS_OPS)
+       if (smmu_domain->smmu->features & ARM_SMMU_FEAT_TRANS_OPS &&
+                       smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
                ret = arm_smmu_iova_to_phys_hard(domain, iova);
-       else
+       } else {
                ret = ops->iova_to_phys(ops, iova);
+       }
+
        spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags);
 
        return ret;
@@ -1556,7 +1559,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
                return -ENODEV;
        }
 
-       if (smmu->version == 1 || (!(id & ID0_ATOSNS) && (id & ID0_S1TS))) {
+       if ((id & ID0_S1TS) && ((smmu->version == 1) || (id & ID0_ATOSNS))) {
                smmu->features |= ARM_SMMU_FEAT_TRANS_OPS;
                dev_notice(smmu->dev, "\taddress translation ops\n");
        }
index ae4c1a854e57896fc64e33668369bebc23f70945..2d1e05bdbb53f5901035294a71c65231b004a338 100644 (file)
@@ -1742,9 +1742,8 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
 
 static void domain_exit(struct dmar_domain *domain)
 {
-       struct dmar_drhd_unit *drhd;
-       struct intel_iommu *iommu;
        struct page *freelist = NULL;
+       int i;
 
        /* Domain 0 is reserved, so dont process it */
        if (!domain)
@@ -1764,8 +1763,8 @@ static void domain_exit(struct dmar_domain *domain)
 
        /* clear attached or cached domains */
        rcu_read_lock();
-       for_each_active_iommu(iommu, drhd)
-               iommu_detach_domain(domain, iommu);
+       for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus)
+               iommu_detach_domain(domain, g_iommus[i]);
        rcu_read_unlock();
 
        dma_free_pagelist(freelist);
index 10186cac7716e246ea8b8a6e915bf07970670f5b..bc39bdf7b99bf170d793965e28777d3c7a279537 100644 (file)
@@ -851,6 +851,7 @@ static int ipmmu_remove(struct platform_device *pdev)
 
 static const struct of_device_id ipmmu_of_ids[] = {
        { .compatible = "renesas,ipmmu-vmsa", },
+       { }
 };
 
 static struct platform_driver ipmmu_driver = {
index 596b0a9eee99a9f2ea1beaac726bddc4069c4937..9687f8afebffbb865256ba6677663e6c76702aa1 100644 (file)
@@ -169,7 +169,7 @@ static void its_encode_cmd(struct its_cmd_block *cmd, u8 cmd_nr)
 
 static void its_encode_devid(struct its_cmd_block *cmd, u32 devid)
 {
-       cmd->raw_cmd[0] &= ~(0xffffUL << 32);
+       cmd->raw_cmd[0] &= BIT_ULL(32) - 1;
        cmd->raw_cmd[0] |= ((u64)devid) << 32;
 }
 
@@ -802,6 +802,7 @@ static int its_alloc_tables(struct its_node *its)
        int i;
        int psz = SZ_64K;
        u64 shr = GITS_BASER_InnerShareable;
+       u64 cache = GITS_BASER_WaWb;
 
        for (i = 0; i < GITS_BASER_NR_REGS; i++) {
                u64 val = readq_relaxed(its->base + GITS_BASER + i * 8);
@@ -848,7 +849,7 @@ retry_baser:
                val = (virt_to_phys(base)                                |
                       (type << GITS_BASER_TYPE_SHIFT)                   |
                       ((entry_size - 1) << GITS_BASER_ENTRY_SIZE_SHIFT) |
-                      GITS_BASER_WaWb                                   |
+                      cache                                             |
                       shr                                               |
                       GITS_BASER_VALID);
 
@@ -874,9 +875,12 @@ retry_baser:
                         * Shareability didn't stick. Just use
                         * whatever the read reported, which is likely
                         * to be the only thing this redistributor
-                        * supports.
+                        * supports. If that's zero, make it
+                        * non-cacheable as well.
                         */
                        shr = tmp & GITS_BASER_SHAREABILITY_MASK;
+                       if (!shr)
+                               cache = GITS_BASER_nC;
                        goto retry_baser;
                }
 
@@ -980,16 +984,39 @@ static void its_cpu_init_lpis(void)
        tmp = readq_relaxed(rbase + GICR_PROPBASER);
 
        if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) {
+               if (!(tmp & GICR_PROPBASER_SHAREABILITY_MASK)) {
+                       /*
+                        * The HW reports non-shareable, we must
+                        * remove the cacheability attributes as
+                        * well.
+                        */
+                       val &= ~(GICR_PROPBASER_SHAREABILITY_MASK |
+                                GICR_PROPBASER_CACHEABILITY_MASK);
+                       val |= GICR_PROPBASER_nC;
+                       writeq_relaxed(val, rbase + GICR_PROPBASER);
+               }
                pr_info_once("GIC: using cache flushing for LPI property table\n");
                gic_rdists->flags |= RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING;
        }
 
        /* set PENDBASE */
        val = (page_to_phys(pend_page) |
-              GICR_PROPBASER_InnerShareable |
-              GICR_PROPBASER_WaWb);
+              GICR_PENDBASER_InnerShareable |
+              GICR_PENDBASER_WaWb);
 
        writeq_relaxed(val, rbase + GICR_PENDBASER);
+       tmp = readq_relaxed(rbase + GICR_PENDBASER);
+
+       if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) {
+               /*
+                * The HW reports non-shareable, we must remove the
+                * cacheability attributes as well.
+                */
+               val &= ~(GICR_PENDBASER_SHAREABILITY_MASK |
+                        GICR_PENDBASER_CACHEABILITY_MASK);
+               val |= GICR_PENDBASER_nC;
+               writeq_relaxed(val, rbase + GICR_PENDBASER);
+       }
 
        /* Enable LPIs */
        val = readl_relaxed(rbase + GICR_CTLR);
@@ -1026,7 +1053,7 @@ static void its_cpu_init_collection(void)
                         * This ITS wants a linear CPU number.
                         */
                        target = readq_relaxed(gic_data_rdist_rd_base() + GICR_TYPER);
-                       target = GICR_TYPER_CPU_NUMBER(target);
+                       target = GICR_TYPER_CPU_NUMBER(target) << 16;
                }
 
                /* Perform collection mapping */
@@ -1422,14 +1449,26 @@ static int its_probe(struct device_node *node, struct irq_domain *parent)
 
        writeq_relaxed(baser, its->base + GITS_CBASER);
        tmp = readq_relaxed(its->base + GITS_CBASER);
-       writeq_relaxed(0, its->base + GITS_CWRITER);
-       writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR);
 
-       if ((tmp ^ baser) & GITS_BASER_SHAREABILITY_MASK) {
+       if ((tmp ^ baser) & GITS_CBASER_SHAREABILITY_MASK) {
+               if (!(tmp & GITS_CBASER_SHAREABILITY_MASK)) {
+                       /*
+                        * The HW reports non-shareable, we must
+                        * remove the cacheability attributes as
+                        * well.
+                        */
+                       baser &= ~(GITS_CBASER_SHAREABILITY_MASK |
+                                  GITS_CBASER_CACHEABILITY_MASK);
+                       baser |= GITS_CBASER_nC;
+                       writeq_relaxed(baser, its->base + GITS_CBASER);
+               }
                pr_info("ITS: using cache flushing for cmd queue\n");
                its->flags |= ITS_FLAGS_CMDQ_NEEDS_FLUSHING;
        }
 
+       writeq_relaxed(0, its->base + GITS_CWRITER);
+       writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR);
+
        if (of_property_read_bool(its->msi_chip.of_node, "msi-controller")) {
                its->domain = irq_domain_add_tree(NULL, &its_domain_ops, its);
                if (!its->domain) {
index ee035ec4526bd802a89de51c6edc099d8bbb9747..169172d2ba05c8b4187b9151975dcd1be52043c2 100644 (file)
@@ -1,6 +1,6 @@
 config LGUEST
        tristate "Linux hypervisor example code"
-       depends on X86_32 && EVENTFD && TTY
+       depends on X86_32 && EVENTFD && TTY && PCI_DIRECT
        select HVC_DRIVER
        ---help---
          This is a very simple module which allows you to run
index 56a5cb0d215203f242b55e7609c4ddf6e7b4bc8f..0d07fca756fee2e8b5b8680b945ff3c2bed188ef 100644 (file)
@@ -2504,7 +2504,6 @@ vpfe_get_pdata(struct platform_device *pdev)
                                             GFP_KERNEL);
                pdata->asd[i]->match_type = V4L2_ASYNC_MATCH_OF;
                pdata->asd[i]->match.of.node = rem;
-               of_node_put(endpoint);
                of_node_put(rem);
        }
 
index cee7b56f840499440142bc598fbd588bd8469f67..f2a3d960b1a60f63dc9586e4f591d9a1574ea8a2 100644 (file)
@@ -1694,7 +1694,6 @@ static void scan_of_host(struct soc_camera_host *ici)
                if (!i)
                        soc_of_bind(ici, epn, ren->parent);
 
-               of_node_put(epn);
                of_node_put(ren);
 
                if (i) {
@@ -1702,6 +1701,8 @@ static void scan_of_host(struct soc_camera_host *ici)
                        break;
                }
        }
+
+       of_node_put(epn);
 }
 
 #else
index b979c265fc51d0a09c48ff4216a8b055ebcd1c26..089a4028859d121d5611d04dde0139196753fb00 100644 (file)
@@ -3850,7 +3850,8 @@ static inline int bond_slave_override(struct bonding *bond,
        /* Find out if any slaves have the same mapping as this skb. */
        bond_for_each_slave_rcu(bond, slave, iter) {
                if (slave->queue_id == skb->queue_mapping) {
-                       if (bond_slave_can_tx(slave)) {
+                       if (bond_slave_is_up(slave) &&
+                           slave->link == BOND_LINK_UP) {
                                bond_dev_queue_xmit(bond, skb, slave->dev);
                                return 0;
                        }
index 80c46ad4cee439d2015b3ee7de66d578f54afd0b..ad0a7e8c2c2bdf33626824645a8180d8e6d900ff 100644 (file)
@@ -592,13 +592,12 @@ static int flexcan_poll_state(struct net_device *dev, u32 reg_esr)
                rx_state = unlikely(reg_esr & FLEXCAN_ESR_RX_WRN) ?
                           CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE;
                new_state = max(tx_state, rx_state);
-       } else if (unlikely(flt == FLEXCAN_ESR_FLT_CONF_PASSIVE)) {
+       } else {
                __flexcan_get_berr_counter(dev, &bec);
-               new_state = CAN_STATE_ERROR_PASSIVE;
+               new_state = flt == FLEXCAN_ESR_FLT_CONF_PASSIVE ?
+                           CAN_STATE_ERROR_PASSIVE : CAN_STATE_BUS_OFF;
                rx_state = bec.rxerr >= bec.txerr ? new_state : 0;
                tx_state = bec.rxerr <= bec.txerr ? new_state : 0;
-       } else {
-               new_state = CAN_STATE_BUS_OFF;
        }
 
        /* state hasn't changed */
@@ -1158,12 +1157,19 @@ static int flexcan_probe(struct platform_device *pdev)
        const struct flexcan_devtype_data *devtype_data;
        struct net_device *dev;
        struct flexcan_priv *priv;
+       struct regulator *reg_xceiver;
        struct resource *mem;
        struct clk *clk_ipg = NULL, *clk_per = NULL;
        void __iomem *base;
        int err, irq;
        u32 clock_freq = 0;
 
+       reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver");
+       if (PTR_ERR(reg_xceiver) == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       else if (IS_ERR(reg_xceiver))
+               reg_xceiver = NULL;
+
        if (pdev->dev.of_node)
                of_property_read_u32(pdev->dev.of_node,
                                                "clock-frequency", &clock_freq);
@@ -1224,9 +1230,7 @@ static int flexcan_probe(struct platform_device *pdev)
        priv->pdata = dev_get_platdata(&pdev->dev);
        priv->devtype_data = devtype_data;
 
-       priv->reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver");
-       if (IS_ERR(priv->reg_xceiver))
-               priv->reg_xceiver = NULL;
+       priv->reg_xceiver = reg_xceiver;
 
        netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT);
 
index 009acc8641fc557cb580cb688983daf041519e4b..8b4d3e6875eb17e6bca38c812132953d0c5ce2c2 100644 (file)
@@ -901,6 +901,8 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *
        }
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
        init_usb_anchor(&dev->rx_submitted);
 
        atomic_set(&dev->active_channels, 0);
index e97a08ce0b90c298577fed09c96dc7a711076e5e..57611fd91229a4580987b3519d56b8913f185411 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
 
-#define MAX_TX_URBS                    16
 #define MAX_RX_URBS                    4
 #define START_TIMEOUT                  1000 /* msecs */
 #define STOP_TIMEOUT                   1000 /* msecs */
@@ -443,6 +442,7 @@ struct kvaser_usb_error_summary {
        };
 };
 
+/* Context for an outstanding, not yet ACKed, transmission */
 struct kvaser_usb_tx_urb_context {
        struct kvaser_usb_net_priv *priv;
        u32 echo_index;
@@ -456,8 +456,13 @@ struct kvaser_usb {
        struct usb_endpoint_descriptor *bulk_in, *bulk_out;
        struct usb_anchor rx_submitted;
 
+       /* @max_tx_urbs: Firmware-reported maximum number of oustanding,
+        * not yet ACKed, transmissions on this device. This value is
+        * also used as a sentinel for marking free tx contexts.
+        */
        u32 fw_version;
        unsigned int nchannels;
+       unsigned int max_tx_urbs;
        enum kvaser_usb_family family;
 
        bool rxinitdone;
@@ -467,19 +472,18 @@ struct kvaser_usb {
 
 struct kvaser_usb_net_priv {
        struct can_priv can;
-
-       spinlock_t tx_contexts_lock;
-       int active_tx_contexts;
-       struct kvaser_usb_tx_urb_context tx_contexts[MAX_TX_URBS];
-
-       struct usb_anchor tx_submitted;
-       struct completion start_comp, stop_comp;
+       struct can_berr_counter bec;
 
        struct kvaser_usb *dev;
        struct net_device *netdev;
        int channel;
 
-       struct can_berr_counter bec;
+       struct completion start_comp, stop_comp;
+       struct usb_anchor tx_submitted;
+
+       spinlock_t tx_contexts_lock;
+       int active_tx_contexts;
+       struct kvaser_usb_tx_urb_context tx_contexts[];
 };
 
 static const struct usb_device_id kvaser_usb_table[] = {
@@ -592,8 +596,8 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
                         * for further details.
                         */
                        if (tmp->len == 0) {
-                               pos = round_up(pos,
-                                              dev->bulk_in->wMaxPacketSize);
+                               pos = round_up(pos, le16_to_cpu(dev->bulk_in->
+                                                               wMaxPacketSize));
                                continue;
                        }
 
@@ -657,9 +661,13 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
        switch (dev->family) {
        case KVASER_LEAF:
                dev->fw_version = le32_to_cpu(msg.u.leaf.softinfo.fw_version);
+               dev->max_tx_urbs =
+                       le16_to_cpu(msg.u.leaf.softinfo.max_outstanding_tx);
                break;
        case KVASER_USBCAN:
                dev->fw_version = le32_to_cpu(msg.u.usbcan.softinfo.fw_version);
+               dev->max_tx_urbs =
+                       le16_to_cpu(msg.u.usbcan.softinfo.max_outstanding_tx);
                break;
        }
 
@@ -715,7 +723,7 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
 
        stats = &priv->netdev->stats;
 
-       context = &priv->tx_contexts[tid % MAX_TX_URBS];
+       context = &priv->tx_contexts[tid % dev->max_tx_urbs];
 
        /* Sometimes the state change doesn't come after a bus-off event */
        if (priv->can.restart_ms &&
@@ -744,7 +752,7 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
        spin_lock_irqsave(&priv->tx_contexts_lock, flags);
 
        can_get_echo_skb(priv->netdev, context->echo_index);
-       context->echo_index = MAX_TX_URBS;
+       context->echo_index = dev->max_tx_urbs;
        --priv->active_tx_contexts;
        netif_wake_queue(priv->netdev);
 
@@ -1329,7 +1337,8 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb)
                 * number of events in case of a heavy rx load on the bus.
                 */
                if (msg->len == 0) {
-                       pos = round_up(pos, dev->bulk_in->wMaxPacketSize);
+                       pos = round_up(pos, le16_to_cpu(dev->bulk_in->
+                                                       wMaxPacketSize));
                        continue;
                }
 
@@ -1512,11 +1521,13 @@ error:
 
 static void kvaser_usb_reset_tx_urb_contexts(struct kvaser_usb_net_priv *priv)
 {
-       int i;
+       int i, max_tx_urbs;
+
+       max_tx_urbs = priv->dev->max_tx_urbs;
 
        priv->active_tx_contexts = 0;
-       for (i = 0; i < MAX_TX_URBS; i++)
-               priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+       for (i = 0; i < max_tx_urbs; i++)
+               priv->tx_contexts[i].echo_index = max_tx_urbs;
 }
 
 /* This method might sleep. Do not call it in the atomic context
@@ -1702,14 +1713,14 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
                *msg_tx_can_flags |= MSG_FLAG_REMOTE_FRAME;
 
        spin_lock_irqsave(&priv->tx_contexts_lock, flags);
-       for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) {
-               if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
+       for (i = 0; i < dev->max_tx_urbs; i++) {
+               if (priv->tx_contexts[i].echo_index == dev->max_tx_urbs) {
                        context = &priv->tx_contexts[i];
 
                        context->echo_index = i;
                        can_put_echo_skb(skb, netdev, context->echo_index);
                        ++priv->active_tx_contexts;
-                       if (priv->active_tx_contexts >= MAX_TX_URBS)
+                       if (priv->active_tx_contexts >= dev->max_tx_urbs)
                                netif_stop_queue(netdev);
 
                        break;
@@ -1743,7 +1754,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
                spin_lock_irqsave(&priv->tx_contexts_lock, flags);
 
                can_free_echo_skb(netdev, context->echo_index);
-               context->echo_index = MAX_TX_URBS;
+               context->echo_index = dev->max_tx_urbs;
                --priv->active_tx_contexts;
                netif_wake_queue(netdev);
 
@@ -1881,7 +1892,9 @@ static int kvaser_usb_init_one(struct usb_interface *intf,
        if (err)
                return err;
 
-       netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
+       netdev = alloc_candev(sizeof(*priv) +
+                             dev->max_tx_urbs * sizeof(*priv->tx_contexts),
+                             dev->max_tx_urbs);
        if (!netdev) {
                dev_err(&intf->dev, "Cannot alloc candev\n");
                return -ENOMEM;
@@ -2009,6 +2022,13 @@ static int kvaser_usb_probe(struct usb_interface *intf,
                return err;
        }
 
+       dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n",
+               ((dev->fw_version >> 24) & 0xff),
+               ((dev->fw_version >> 16) & 0xff),
+               (dev->fw_version & 0xffff));
+
+       dev_dbg(&intf->dev, "Max oustanding tx = %d URBs\n", dev->max_tx_urbs);
+
        err = kvaser_usb_get_card_info(dev);
        if (err) {
                dev_err(&intf->dev,
@@ -2016,11 +2036,6 @@ static int kvaser_usb_probe(struct usb_interface *intf,
                return err;
        }
 
-       dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n",
-               ((dev->fw_version >> 24) & 0xff),
-               ((dev->fw_version >> 16) & 0xff),
-               (dev->fw_version & 0xffff));
-
        for (i = 0; i < dev->nchannels; i++) {
                err = kvaser_usb_init_one(intf, id, i);
                if (err) {
index 1ba7c25002e1e27ec1a9333412c175edb0f5594a..e8fc4952c6b074f80a2af132d2bc161e7fd3d8c7 100644 (file)
@@ -26,8 +26,8 @@
 #define PUCAN_CMD_FILTER_STD           0x008
 #define PUCAN_CMD_TX_ABORT             0x009
 #define PUCAN_CMD_WR_ERR_CNT           0x00a
-#define PUCAN_CMD_RX_FRAME_ENABLE      0x00b
-#define PUCAN_CMD_RX_FRAME_DISABLE     0x00c
+#define PUCAN_CMD_SET_EN_OPTION                0x00b
+#define PUCAN_CMD_CLR_DIS_OPTION       0x00c
 #define PUCAN_CMD_END_OF_COLLECTION    0x3ff
 
 /* uCAN received messages list */
@@ -101,14 +101,15 @@ struct __packed pucan_wr_err_cnt {
        u16     unused;
 };
 
-/* uCAN RX_FRAME_ENABLE command fields */
-#define PUCAN_FLTEXT_ERROR             0x0001
-#define PUCAN_FLTEXT_BUSLOAD           0x0002
+/* uCAN SET_EN/CLR_DIS _OPTION command fields */
+#define PUCAN_OPTION_ERROR             0x0001
+#define PUCAN_OPTION_BUSLOAD           0x0002
+#define PUCAN_OPTION_CANDFDISO         0x0004
 
-struct __packed pucan_filter_ext {
+struct __packed pucan_options {
        __le16  opcode_channel;
 
-       __le16  ext_mask;
+       __le16  options;
        u32     unused;
 };
 
index 0bac0f14edc3cd73727b4a0d9f0776d857c4ba8c..a9221ad9f1a0a0387de1ebf8470c0d360e895773 100644 (file)
@@ -110,13 +110,13 @@ struct __packed pcan_ufd_led {
        u8      unused[5];
 };
 
-/* Extended usage of uCAN commands CMD_RX_FRAME_xxxABLE for PCAN-USB Pro FD */
+/* Extended usage of uCAN commands CMD_xxx_xx_OPTION for PCAN-USB Pro FD */
 #define PCAN_UFD_FLTEXT_CALIBRATION    0x8000
 
-struct __packed pcan_ufd_filter_ext {
+struct __packed pcan_ufd_options {
        __le16  opcode_channel;
 
-       __le16  ext_mask;
+       __le16  ucan_mask;
        u16     unused;
        __le16  usb_mask;
 };
@@ -251,6 +251,27 @@ static int pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf)
        /* moves the pointer forward */
        pc += sizeof(struct pucan_wr_err_cnt);
 
+       /* add command to switch from ISO to non-ISO mode, if fw allows it */
+       if (dev->can.ctrlmode_supported & CAN_CTRLMODE_FD_NON_ISO) {
+               struct pucan_options *puo = (struct pucan_options *)pc;
+
+               puo->opcode_channel =
+                       (dev->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) ?
+                       pucan_cmd_opcode_channel(dev,
+                                                PUCAN_CMD_CLR_DIS_OPTION) :
+                       pucan_cmd_opcode_channel(dev, PUCAN_CMD_SET_EN_OPTION);
+
+               puo->options = cpu_to_le16(PUCAN_OPTION_CANDFDISO);
+
+               /* to be sure that no other extended bits will be taken into
+                * account
+                */
+               puo->unused = 0;
+
+               /* moves the pointer forward */
+               pc += sizeof(struct pucan_options);
+       }
+
        /* next, go back to operational mode */
        cmd = (struct pucan_command *)pc;
        cmd->opcode_channel = pucan_cmd_opcode_channel(dev,
@@ -321,21 +342,21 @@ static int pcan_usb_fd_set_filter_std(struct peak_usb_device *dev, int idx,
        return pcan_usb_fd_send_cmd(dev, cmd);
 }
 
-/* set/unset notifications filter:
+/* set/unset options
  *
- *     onoff   sets(1)/unset(0) notifications
- *     mask    each bit defines a kind of notification to set/unset
+ *     onoff   set(1)/unset(0) options
+ *     mask    each bit defines a kind of options to set/unset
  */
-static int pcan_usb_fd_set_filter_ext(struct peak_usb_device *dev,
-                                     bool onoff, u16 ext_mask, u16 usb_mask)
+static int pcan_usb_fd_set_options(struct peak_usb_device *dev,
+                                  bool onoff, u16 ucan_mask, u16 usb_mask)
 {
-       struct pcan_ufd_filter_ext *cmd = pcan_usb_fd_cmd_buffer(dev);
+       struct pcan_ufd_options *cmd = pcan_usb_fd_cmd_buffer(dev);
 
        cmd->opcode_channel = pucan_cmd_opcode_channel(dev,
-                                       (onoff) ? PUCAN_CMD_RX_FRAME_ENABLE :
-                                                 PUCAN_CMD_RX_FRAME_DISABLE);
+                                       (onoff) ? PUCAN_CMD_SET_EN_OPTION :
+                                                 PUCAN_CMD_CLR_DIS_OPTION);
 
-       cmd->ext_mask = cpu_to_le16(ext_mask);
+       cmd->ucan_mask = cpu_to_le16(ucan_mask);
        cmd->usb_mask = cpu_to_le16(usb_mask);
 
        /* send the command */
@@ -770,9 +791,9 @@ static int pcan_usb_fd_start(struct peak_usb_device *dev)
                                       &pcan_usb_pro_fd);
 
                /* enable USB calibration messages */
-               err = pcan_usb_fd_set_filter_ext(dev, 1,
-                                                PUCAN_FLTEXT_ERROR,
-                                                PCAN_UFD_FLTEXT_CALIBRATION);
+               err = pcan_usb_fd_set_options(dev, 1,
+                                             PUCAN_OPTION_ERROR,
+                                             PCAN_UFD_FLTEXT_CALIBRATION);
        }
 
        pdev->usb_if->dev_opened_count++;
@@ -806,9 +827,9 @@ static int pcan_usb_fd_stop(struct peak_usb_device *dev)
 
        /* turn off special msgs for that interface if no other dev opened */
        if (pdev->usb_if->dev_opened_count == 1)
-               pcan_usb_fd_set_filter_ext(dev, 0,
-                                          PUCAN_FLTEXT_ERROR,
-                                          PCAN_UFD_FLTEXT_CALIBRATION);
+               pcan_usb_fd_set_options(dev, 0,
+                                       PUCAN_OPTION_ERROR,
+                                       PCAN_UFD_FLTEXT_CALIBRATION);
        pdev->usb_if->dev_opened_count--;
 
        return 0;
@@ -860,8 +881,14 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev)
                         pdev->usb_if->fw_info.fw_version[2],
                         dev->adapter->ctrl_count);
 
-               /* the currently supported hw is non-ISO */
-               dev->can.ctrlmode = CAN_CTRLMODE_FD_NON_ISO;
+               /* check for ability to switch between ISO/non-ISO modes */
+               if (pdev->usb_if->fw_info.fw_version[0] >= 2) {
+                       /* firmware >= 2.x supports ISO/non-ISO switching */
+                       dev->can.ctrlmode_supported |= CAN_CTRLMODE_FD_NON_ISO;
+               } else {
+                       /* firmware < 2.x only supports fixed(!) non-ISO */
+                       dev->can.ctrlmode |= CAN_CTRLMODE_FD_NON_ISO;
+               }
 
                /* tell the hardware the can driver is running */
                err = pcan_usb_fd_drv_loaded(dev, 1);
@@ -937,9 +964,9 @@ static void pcan_usb_fd_exit(struct peak_usb_device *dev)
        if (dev->ctrl_idx == 0) {
                /* turn off calibration message if any device were opened */
                if (pdev->usb_if->dev_opened_count > 0)
-                       pcan_usb_fd_set_filter_ext(dev, 0,
-                                                  PUCAN_FLTEXT_ERROR,
-                                                  PCAN_UFD_FLTEXT_CALIBRATION);
+                       pcan_usb_fd_set_options(dev, 0,
+                                               PUCAN_OPTION_ERROR,
+                                               PCAN_UFD_FLTEXT_CALIBRATION);
 
                /* tell USB adapter that the driver is being unloaded */
                pcan_usb_fd_drv_loaded(dev, 0);
index 756053c028becff93c62cfcdbd6e1f635594cc01..4085c4b310470b6ebf718121fa423d2995dcb8ef 100644 (file)
@@ -1811,7 +1811,7 @@ struct bnx2x {
        int                     stats_state;
 
        /* used for synchronization of concurrent threads statistics handling */
-       spinlock_t              stats_lock;
+       struct mutex            stats_lock;
 
        /* used by dmae command loader */
        struct dmae_command     stats_dmae;
@@ -1935,8 +1935,6 @@ struct bnx2x {
 
        int fp_array_size;
        u32 dump_preset_idx;
-       bool                                    stats_started;
-       struct semaphore                        stats_sema;
 
        u8                                      phys_port_id[ETH_ALEN];
 
index 996e215fc3246c4fba6f1714ddceb69b88f179be..1ec635f549944f87e0c0df4eb0816dcf33d90706 100644 (file)
@@ -129,8 +129,8 @@ struct bnx2x_mac_vals {
        u32 xmac_val;
        u32 emac_addr;
        u32 emac_val;
-       u32 umac_addr;
-       u32 umac_val;
+       u32 umac_addr[2];
+       u32 umac_val[2];
        u32 bmac_addr;
        u32 bmac_val[2];
 };
@@ -7866,6 +7866,20 @@ int bnx2x_init_hw_func_cnic(struct bnx2x *bp)
        return 0;
 }
 
+/* previous driver DMAE transaction may have occurred when pre-boot stage ended
+ * and boot began, or when kdump kernel was loaded. Either case would invalidate
+ * the addresses of the transaction, resulting in was-error bit set in the pci
+ * causing all hw-to-host pcie transactions to timeout. If this happened we want
+ * to clear the interrupt which detected this from the pglueb and the was done
+ * bit
+ */
+static void bnx2x_clean_pglue_errors(struct bnx2x *bp)
+{
+       if (!CHIP_IS_E1x(bp))
+               REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR,
+                      1 << BP_ABS_FUNC(bp));
+}
+
 static int bnx2x_init_hw_func(struct bnx2x *bp)
 {
        int port = BP_PORT(bp);
@@ -7958,8 +7972,7 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
 
        bnx2x_init_block(bp, BLOCK_PGLUE_B, init_phase);
 
-       if (!CHIP_IS_E1x(bp))
-               REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, func);
+       bnx2x_clean_pglue_errors(bp);
 
        bnx2x_init_block(bp, BLOCK_ATC, init_phase);
        bnx2x_init_block(bp, BLOCK_DMAE, init_phase);
@@ -10141,6 +10154,25 @@ static u32 bnx2x_get_pretend_reg(struct bnx2x *bp)
        return base + (BP_ABS_FUNC(bp)) * stride;
 }
 
+static bool bnx2x_prev_unload_close_umac(struct bnx2x *bp,
+                                        u8 port, u32 reset_reg,
+                                        struct bnx2x_mac_vals *vals)
+{
+       u32 mask = MISC_REGISTERS_RESET_REG_2_UMAC0 << port;
+       u32 base_addr;
+
+       if (!(mask & reset_reg))
+               return false;
+
+       BNX2X_DEV_INFO("Disable umac Rx %02x\n", port);
+       base_addr = port ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
+       vals->umac_addr[port] = base_addr + UMAC_REG_COMMAND_CONFIG;
+       vals->umac_val[port] = REG_RD(bp, vals->umac_addr[port]);
+       REG_WR(bp, vals->umac_addr[port], 0);
+
+       return true;
+}
+
 static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
                                        struct bnx2x_mac_vals *vals)
 {
@@ -10149,10 +10181,7 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
        u8 port = BP_PORT(bp);
 
        /* reset addresses as they also mark which values were changed */
-       vals->bmac_addr = 0;
-       vals->umac_addr = 0;
-       vals->xmac_addr = 0;
-       vals->emac_addr = 0;
+       memset(vals, 0, sizeof(*vals));
 
        reset_reg = REG_RD(bp, MISC_REG_RESET_REG_2);
 
@@ -10201,15 +10230,11 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
                        REG_WR(bp, vals->xmac_addr, 0);
                        mac_stopped = true;
                }
-               mask = MISC_REGISTERS_RESET_REG_2_UMAC0 << port;
-               if (mask & reset_reg) {
-                       BNX2X_DEV_INFO("Disable umac Rx\n");
-                       base_addr = BP_PORT(bp) ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
-                       vals->umac_addr = base_addr + UMAC_REG_COMMAND_CONFIG;
-                       vals->umac_val = REG_RD(bp, vals->umac_addr);
-                       REG_WR(bp, vals->umac_addr, 0);
-                       mac_stopped = true;
-               }
+
+               mac_stopped |= bnx2x_prev_unload_close_umac(bp, 0,
+                                                           reset_reg, vals);
+               mac_stopped |= bnx2x_prev_unload_close_umac(bp, 1,
+                                                           reset_reg, vals);
        }
 
        if (mac_stopped)
@@ -10505,8 +10530,11 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
                /* Close the MAC Rx to prevent BRB from filling up */
                bnx2x_prev_unload_close_mac(bp, &mac_vals);
 
-               /* close LLH filters towards the BRB */
+               /* close LLH filters for both ports towards the BRB */
                bnx2x_set_rx_filter(&bp->link_params, 0);
+               bp->link_params.port ^= 1;
+               bnx2x_set_rx_filter(&bp->link_params, 0);
+               bp->link_params.port ^= 1;
 
                /* Check if the UNDI driver was previously loaded */
                if (bnx2x_prev_is_after_undi(bp)) {
@@ -10553,8 +10581,10 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
 
        if (mac_vals.xmac_addr)
                REG_WR(bp, mac_vals.xmac_addr, mac_vals.xmac_val);
-       if (mac_vals.umac_addr)
-               REG_WR(bp, mac_vals.umac_addr, mac_vals.umac_val);
+       if (mac_vals.umac_addr[0])
+               REG_WR(bp, mac_vals.umac_addr[0], mac_vals.umac_val[0]);
+       if (mac_vals.umac_addr[1])
+               REG_WR(bp, mac_vals.umac_addr[1], mac_vals.umac_val[1]);
        if (mac_vals.emac_addr)
                REG_WR(bp, mac_vals.emac_addr, mac_vals.emac_val);
        if (mac_vals.bmac_addr) {
@@ -10571,26 +10601,6 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
        return bnx2x_prev_mcp_done(bp);
 }
 
-/* previous driver DMAE transaction may have occurred when pre-boot stage ended
- * and boot began, or when kdump kernel was loaded. Either case would invalidate
- * the addresses of the transaction, resulting in was-error bit set in the pci
- * causing all hw-to-host pcie transactions to timeout. If this happened we want
- * to clear the interrupt which detected this from the pglueb and the was done
- * bit
- */
-static void bnx2x_prev_interrupted_dmae(struct bnx2x *bp)
-{
-       if (!CHIP_IS_E1x(bp)) {
-               u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS);
-               if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) {
-                       DP(BNX2X_MSG_SP,
-                          "'was error' bit was found to be set in pglueb upon startup. Clearing\n");
-                       REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR,
-                              1 << BP_FUNC(bp));
-               }
-       }
-}
-
 static int bnx2x_prev_unload(struct bnx2x *bp)
 {
        int time_counter = 10;
@@ -10600,7 +10610,7 @@ static int bnx2x_prev_unload(struct bnx2x *bp)
        /* clear hw from errors which may have resulted from an interrupted
         * dmae transaction.
         */
-       bnx2x_prev_interrupted_dmae(bp);
+       bnx2x_clean_pglue_errors(bp);
 
        /* Release previously held locks */
        hw_lock_reg = (BP_FUNC(bp) <= 5) ?
@@ -12037,9 +12047,8 @@ static int bnx2x_init_bp(struct bnx2x *bp)
        mutex_init(&bp->port.phy_mutex);
        mutex_init(&bp->fw_mb_mutex);
        mutex_init(&bp->drv_info_mutex);
+       mutex_init(&bp->stats_lock);
        bp->drv_info_mng_owner = false;
-       spin_lock_init(&bp->stats_lock);
-       sema_init(&bp->stats_sema, 1);
 
        INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
        INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task);
@@ -13668,9 +13677,9 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
        cancel_delayed_work_sync(&bp->sp_task);
        cancel_delayed_work_sync(&bp->period_task);
 
-       spin_lock_bh(&bp->stats_lock);
+       mutex_lock(&bp->stats_lock);
        bp->stats_state = STATS_STATE_DISABLED;
-       spin_unlock_bh(&bp->stats_lock);
+       mutex_unlock(&bp->stats_lock);
 
        bnx2x_save_statistics(bp);
 
index e5aca2de1871350f3e47a788c4360b461c02a039..cfe3c7695455e16eab516e0f99db6ee6b7e58879 100644 (file)
@@ -2238,7 +2238,9 @@ int bnx2x_vf_close(struct bnx2x *bp, struct bnx2x_virtf *vf)
 
                cookie.vf = vf;
                cookie.state = VF_ACQUIRED;
-               bnx2x_stats_safe_exec(bp, bnx2x_set_vf_state, &cookie);
+               rc = bnx2x_stats_safe_exec(bp, bnx2x_set_vf_state, &cookie);
+               if (rc)
+                       goto op_err;
        }
 
        DP(BNX2X_MSG_IOV, "set state to acquired\n");
index d1608297c773746237a8faf3697277afcbe45918..800ab44a07cecd721c8b12f0c5b8602e1124a0dd 100644 (file)
@@ -123,36 +123,28 @@ static void bnx2x_dp_stats(struct bnx2x *bp)
  */
 static void bnx2x_storm_stats_post(struct bnx2x *bp)
 {
-       if (!bp->stats_pending) {
-               int rc;
+       int rc;
 
-               spin_lock_bh(&bp->stats_lock);
-
-               if (bp->stats_pending) {
-                       spin_unlock_bh(&bp->stats_lock);
-                       return;
-               }
-
-               bp->fw_stats_req->hdr.drv_stats_counter =
-                       cpu_to_le16(bp->stats_counter++);
+       if (bp->stats_pending)
+               return;
 
-               DP(BNX2X_MSG_STATS, "Sending statistics ramrod %d\n",
-                  le16_to_cpu(bp->fw_stats_req->hdr.drv_stats_counter));
+       bp->fw_stats_req->hdr.drv_stats_counter =
+               cpu_to_le16(bp->stats_counter++);
 
-               /* adjust the ramrod to include VF queues statistics */
-               bnx2x_iov_adjust_stats_req(bp);
-               bnx2x_dp_stats(bp);
+       DP(BNX2X_MSG_STATS, "Sending statistics ramrod %d\n",
+          le16_to_cpu(bp->fw_stats_req->hdr.drv_stats_counter));
 
-               /* send FW stats ramrod */
-               rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STAT_QUERY, 0,
-                                  U64_HI(bp->fw_stats_req_mapping),
-                                  U64_LO(bp->fw_stats_req_mapping),
-                                  NONE_CONNECTION_TYPE);
-               if (rc == 0)
-                       bp->stats_pending = 1;
+       /* adjust the ramrod to include VF queues statistics */
+       bnx2x_iov_adjust_stats_req(bp);
+       bnx2x_dp_stats(bp);
 
-               spin_unlock_bh(&bp->stats_lock);
-       }
+       /* send FW stats ramrod */
+       rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STAT_QUERY, 0,
+                          U64_HI(bp->fw_stats_req_mapping),
+                          U64_LO(bp->fw_stats_req_mapping),
+                          NONE_CONNECTION_TYPE);
+       if (rc == 0)
+               bp->stats_pending = 1;
 }
 
 static void bnx2x_hw_stats_post(struct bnx2x *bp)
@@ -221,7 +213,7 @@ static void bnx2x_stats_comp(struct bnx2x *bp)
  */
 
 /* should be called under stats_sema */
-static void __bnx2x_stats_pmf_update(struct bnx2x *bp)
+static void bnx2x_stats_pmf_update(struct bnx2x *bp)
 {
        struct dmae_command *dmae;
        u32 opcode;
@@ -519,7 +511,7 @@ static void bnx2x_func_stats_init(struct bnx2x *bp)
 }
 
 /* should be called under stats_sema */
-static void __bnx2x_stats_start(struct bnx2x *bp)
+static void bnx2x_stats_start(struct bnx2x *bp)
 {
        if (IS_PF(bp)) {
                if (bp->port.pmf)
@@ -531,34 +523,13 @@ static void __bnx2x_stats_start(struct bnx2x *bp)
                bnx2x_hw_stats_post(bp);
                bnx2x_storm_stats_post(bp);
        }
-
-       bp->stats_started = true;
-}
-
-static void bnx2x_stats_start(struct bnx2x *bp)
-{
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
-       __bnx2x_stats_start(bp);
-       up(&bp->stats_sema);
 }
 
 static void bnx2x_stats_pmf_start(struct bnx2x *bp)
 {
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
        bnx2x_stats_comp(bp);
-       __bnx2x_stats_pmf_update(bp);
-       __bnx2x_stats_start(bp);
-       up(&bp->stats_sema);
-}
-
-static void bnx2x_stats_pmf_update(struct bnx2x *bp)
-{
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
-       __bnx2x_stats_pmf_update(bp);
-       up(&bp->stats_sema);
+       bnx2x_stats_pmf_update(bp);
+       bnx2x_stats_start(bp);
 }
 
 static void bnx2x_stats_restart(struct bnx2x *bp)
@@ -568,11 +539,9 @@ static void bnx2x_stats_restart(struct bnx2x *bp)
         */
        if (IS_VF(bp))
                return;
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
+
        bnx2x_stats_comp(bp);
-       __bnx2x_stats_start(bp);
-       up(&bp->stats_sema);
+       bnx2x_stats_start(bp);
 }
 
 static void bnx2x_bmac_stats_update(struct bnx2x *bp)
@@ -1246,18 +1215,12 @@ static void bnx2x_stats_update(struct bnx2x *bp)
 {
        u32 *stats_comp = bnx2x_sp(bp, stats_comp);
 
-       /* we run update from timer context, so give up
-        * if somebody is in the middle of transition
-        */
-       if (down_trylock(&bp->stats_sema))
+       if (bnx2x_edebug_stats_stopped(bp))
                return;
 
-       if (bnx2x_edebug_stats_stopped(bp) || !bp->stats_started)
-               goto out;
-
        if (IS_PF(bp)) {
                if (*stats_comp != DMAE_COMP_VAL)
-                       goto out;
+                       return;
 
                if (bp->port.pmf)
                        bnx2x_hw_stats_update(bp);
@@ -1267,7 +1230,7 @@ static void bnx2x_stats_update(struct bnx2x *bp)
                                BNX2X_ERR("storm stats were not updated for 3 times\n");
                                bnx2x_panic();
                        }
-                       goto out;
+                       return;
                }
        } else {
                /* vf doesn't collect HW statistics, and doesn't get completions
@@ -1281,7 +1244,7 @@ static void bnx2x_stats_update(struct bnx2x *bp)
 
        /* vf is done */
        if (IS_VF(bp))
-               goto out;
+               return;
 
        if (netif_msg_timer(bp)) {
                struct bnx2x_eth_stats *estats = &bp->eth_stats;
@@ -1292,9 +1255,6 @@ static void bnx2x_stats_update(struct bnx2x *bp)
 
        bnx2x_hw_stats_post(bp);
        bnx2x_storm_stats_post(bp);
-
-out:
-       up(&bp->stats_sema);
 }
 
 static void bnx2x_port_stats_stop(struct bnx2x *bp)
@@ -1358,12 +1318,7 @@ static void bnx2x_port_stats_stop(struct bnx2x *bp)
 
 static void bnx2x_stats_stop(struct bnx2x *bp)
 {
-       int update = 0;
-
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
-
-       bp->stats_started = false;
+       bool update = false;
 
        bnx2x_stats_comp(bp);
 
@@ -1381,8 +1336,6 @@ static void bnx2x_stats_stop(struct bnx2x *bp)
                bnx2x_hw_stats_post(bp);
                bnx2x_stats_comp(bp);
        }
-
-       up(&bp->stats_sema);
 }
 
 static void bnx2x_stats_do_nothing(struct bnx2x *bp)
@@ -1410,18 +1363,28 @@ static const struct {
 
 void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
 {
-       enum bnx2x_stats_state state;
-       void (*action)(struct bnx2x *bp);
+       enum bnx2x_stats_state state = bp->stats_state;
+
        if (unlikely(bp->panic))
                return;
 
-       spin_lock_bh(&bp->stats_lock);
-       state = bp->stats_state;
+       /* Statistics update run from timer context, and we don't want to stop
+        * that context in case someone is in the middle of a transition.
+        * For other events, wait a bit until lock is taken.
+        */
+       if (!mutex_trylock(&bp->stats_lock)) {
+               if (event == STATS_EVENT_UPDATE)
+                       return;
+
+               DP(BNX2X_MSG_STATS,
+                  "Unlikely stats' lock contention [event %d]\n", event);
+               mutex_lock(&bp->stats_lock);
+       }
+
+       bnx2x_stats_stm[state][event].action(bp);
        bp->stats_state = bnx2x_stats_stm[state][event].next_state;
-       action = bnx2x_stats_stm[state][event].action;
-       spin_unlock_bh(&bp->stats_lock);
 
-       action(bp);
+       mutex_unlock(&bp->stats_lock);
 
        if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
                DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
@@ -1998,13 +1961,34 @@ void bnx2x_afex_collect_stats(struct bnx2x *bp, void *void_afex_stats,
        }
 }
 
-void bnx2x_stats_safe_exec(struct bnx2x *bp,
-                          void (func_to_exec)(void *cookie),
-                          void *cookie){
-       if (down_timeout(&bp->stats_sema, HZ/10))
-               BNX2X_ERR("Unable to acquire stats lock\n");
+int bnx2x_stats_safe_exec(struct bnx2x *bp,
+                         void (func_to_exec)(void *cookie),
+                         void *cookie)
+{
+       int cnt = 10, rc = 0;
+
+       /* Wait for statistics to end [while blocking further requests],
+        * then run supplied function 'safely'.
+        */
+       mutex_lock(&bp->stats_lock);
+
        bnx2x_stats_comp(bp);
+       while (bp->stats_pending && cnt--)
+               if (bnx2x_storm_stats_update(bp))
+                       usleep_range(1000, 2000);
+       if (bp->stats_pending) {
+               BNX2X_ERR("Failed to wait for stats pending to clear [possibly FW is stuck]\n");
+               rc = -EBUSY;
+               goto out;
+       }
+
        func_to_exec(cookie);
-       __bnx2x_stats_start(bp);
-       up(&bp->stats_sema);
+
+out:
+       /* No need to restart statistics - if they're enabled, the timer
+        * will restart the statistics.
+        */
+       mutex_unlock(&bp->stats_lock);
+
+       return rc;
 }
index 2beceaefdeea7aa5ac53f6a3028cd0fbcacbc51a..965539a9dabe7e4702e1ba6b382aefc69fb26fac 100644 (file)
@@ -539,9 +539,9 @@ struct bnx2x;
 void bnx2x_memset_stats(struct bnx2x *bp);
 void bnx2x_stats_init(struct bnx2x *bp);
 void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event);
-void bnx2x_stats_safe_exec(struct bnx2x *bp,
-                          void (func_to_exec)(void *cookie),
-                          void *cookie);
+int bnx2x_stats_safe_exec(struct bnx2x *bp,
+                         void (func_to_exec)(void *cookie),
+                         void *cookie);
 
 /**
  * bnx2x_save_statistics - save statistics when unloading.
index 97842d03675b327d65f564b351f24d12bf72c18b..c6ff4890d171a1509c7b3ca2aa21e5b0edd6039f 100644 (file)
@@ -376,8 +376,6 @@ enum {
 enum {
        INGQ_EXTRAS = 2,        /* firmware event queue and */
                                /*   forwarded interrupts */
-       MAX_EGRQ = MAX_ETH_QSETS*2 + MAX_OFLD_QSETS*2
-                  + MAX_CTRL_QUEUES + MAX_RDMA_QUEUES + MAX_ISCSI_QUEUES,
        MAX_INGQ = MAX_ETH_QSETS + MAX_OFLD_QSETS + MAX_RDMA_QUEUES
                   + MAX_RDMA_CIQS + MAX_ISCSI_QUEUES + INGQ_EXTRAS,
 };
@@ -616,11 +614,13 @@ struct sge {
        unsigned int idma_qid[2];   /* SGE IDMA Hung Ingress Queue ID */
 
        unsigned int egr_start;
+       unsigned int egr_sz;
        unsigned int ingr_start;
-       void *egr_map[MAX_EGRQ];    /* qid->queue egress queue map */
-       struct sge_rspq *ingr_map[MAX_INGQ]; /* qid->queue ingress queue map */
-       DECLARE_BITMAP(starving_fl, MAX_EGRQ);
-       DECLARE_BITMAP(txq_maperr, MAX_EGRQ);
+       unsigned int ingr_sz;
+       void **egr_map;    /* qid->queue egress queue map */
+       struct sge_rspq **ingr_map; /* qid->queue ingress queue map */
+       unsigned long *starving_fl;
+       unsigned long *txq_maperr;
        struct timer_list rx_timer; /* refills starving FLs */
        struct timer_list tx_timer; /* checks Tx queues */
 };
@@ -1136,6 +1136,8 @@ int cxgb4_t4_bar2_sge_qregs(struct adapter *adapter,
 
 unsigned int qtimer_val(const struct adapter *adap,
                        const struct sge_rspq *q);
+
+int t4_init_devlog_params(struct adapter *adapter);
 int t4_init_sge_params(struct adapter *adapter);
 int t4_init_tp_params(struct adapter *adap);
 int t4_filter_field_shift(const struct adapter *adap, int filter_sel);
index 78854ceb0870a29004ab04261fa26b296b958d4e..dcb0479452907abd43732aa9332f927f7f0c3ef3 100644 (file)
@@ -670,9 +670,13 @@ static int cctrl_tbl_show(struct seq_file *seq, void *v)
                "0.9375" };
 
        int i;
-       u16 incr[NMTUS][NCCTRL_WIN];
+       u16 (*incr)[NCCTRL_WIN];
        struct adapter *adap = seq->private;
 
+       incr = kmalloc(sizeof(*incr) * NMTUS, GFP_KERNEL);
+       if (!incr)
+               return -ENOMEM;
+
        t4_read_cong_tbl(adap, incr);
 
        for (i = 0; i < NCCTRL_WIN; ++i) {
@@ -685,6 +689,8 @@ static int cctrl_tbl_show(struct seq_file *seq, void *v)
                           adap->params.a_wnd[i],
                           dec_fac[adap->params.b_wnd[i]]);
        }
+
+       kfree(incr);
        return 0;
 }
 
index a22cf932ca3536920798ef50241fd9b43c26857a..d92995138f7ef9253c3b2ac37efba2c491e2f528 100644 (file)
@@ -920,7 +920,7 @@ static void quiesce_rx(struct adapter *adap)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) {
+       for (i = 0; i < adap->sge.ingr_sz; i++) {
                struct sge_rspq *q = adap->sge.ingr_map[i];
 
                if (q && q->handler) {
@@ -934,6 +934,21 @@ static void quiesce_rx(struct adapter *adap)
        }
 }
 
+/* Disable interrupt and napi handler */
+static void disable_interrupts(struct adapter *adap)
+{
+       if (adap->flags & FULL_INIT_DONE) {
+               t4_intr_disable(adap);
+               if (adap->flags & USING_MSIX) {
+                       free_msix_queue_irqs(adap);
+                       free_irq(adap->msix_info[0].vec, adap);
+               } else {
+                       free_irq(adap->pdev->irq, adap);
+               }
+               quiesce_rx(adap);
+       }
+}
+
 /*
  * Enable NAPI scheduling and interrupt generation for all Rx queues.
  */
@@ -941,7 +956,7 @@ static void enable_rx(struct adapter *adap)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) {
+       for (i = 0; i < adap->sge.ingr_sz; i++) {
                struct sge_rspq *q = adap->sge.ingr_map[i];
 
                if (!q)
@@ -970,8 +985,8 @@ static int setup_sge_queues(struct adapter *adap)
        int err, msi_idx, i, j;
        struct sge *s = &adap->sge;
 
-       bitmap_zero(s->starving_fl, MAX_EGRQ);
-       bitmap_zero(s->txq_maperr, MAX_EGRQ);
+       bitmap_zero(s->starving_fl, s->egr_sz);
+       bitmap_zero(s->txq_maperr, s->egr_sz);
 
        if (adap->flags & USING_MSIX)
                msi_idx = 1;         /* vector 0 is for non-queue interrupts */
@@ -983,6 +998,19 @@ static int setup_sge_queues(struct adapter *adap)
                msi_idx = -((int)s->intrq.abs_id + 1);
        }
 
+       /* NOTE: If you add/delete any Ingress/Egress Queue allocations in here,
+        * don't forget to update the following which need to be
+        * synchronized to and changes here.
+        *
+        * 1. The calculations of MAX_INGQ in cxgb4.h.
+        *
+        * 2. Update enable_msix/name_msix_vecs/request_msix_queue_irqs
+        *    to accommodate any new/deleted Ingress Queues
+        *    which need MSI-X Vectors.
+        *
+        * 3. Update sge_qinfo_show() to include information on the
+        *    new/deleted queues.
+        */
        err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0],
                               msi_idx, NULL, fwevtq_handler);
        if (err) {
@@ -4244,19 +4272,12 @@ static int cxgb_up(struct adapter *adap)
 
 static void cxgb_down(struct adapter *adapter)
 {
-       t4_intr_disable(adapter);
        cancel_work_sync(&adapter->tid_release_task);
        cancel_work_sync(&adapter->db_full_task);
        cancel_work_sync(&adapter->db_drop_task);
        adapter->tid_release_task_busy = false;
        adapter->tid_release_head = NULL;
 
-       if (adapter->flags & USING_MSIX) {
-               free_msix_queue_irqs(adapter);
-               free_irq(adapter->msix_info[0].vec, adapter);
-       } else
-               free_irq(adapter->pdev->irq, adapter);
-       quiesce_rx(adapter);
        t4_sge_stop(adapter);
        t4_free_sge_resources(adapter);
        adapter->flags &= ~FULL_INIT_DONE;
@@ -4733,8 +4754,9 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
        if (ret < 0)
                return ret;
 
-       ret = t4_cfg_pfvf(adap, adap->fn, adap->fn, 0, MAX_EGRQ, 64, MAX_INGQ,
-                         0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF, FW_CMD_CAP_PF);
+       ret = t4_cfg_pfvf(adap, adap->fn, adap->fn, 0, adap->sge.egr_sz, 64,
+                         MAX_INGQ, 0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF,
+                         FW_CMD_CAP_PF);
        if (ret < 0)
                return ret;
 
@@ -5088,10 +5110,15 @@ static int adap_init0(struct adapter *adap)
        enum dev_state state;
        u32 params[7], val[7];
        struct fw_caps_config_cmd caps_cmd;
-       struct fw_devlog_cmd devlog_cmd;
-       u32 devlog_meminfo;
        int reset = 1;
 
+       /* Grab Firmware Device Log parameters as early as possible so we have
+        * access to it for debugging, etc.
+        */
+       ret = t4_init_devlog_params(adap);
+       if (ret < 0)
+               return ret;
+
        /* Contact FW, advertising Master capability */
        ret = t4_fw_hello(adap, adap->mbox, adap->mbox, MASTER_MAY, &state);
        if (ret < 0) {
@@ -5169,30 +5196,6 @@ static int adap_init0(struct adapter *adap)
        if (ret < 0)
                goto bye;
 
-       /* Read firmware device log parameters.  We really need to find a way
-        * to get these parameters initialized with some default values (which
-        * are likely to be correct) for the case where we either don't
-        * attache to the firmware or it's crashed when we probe the adapter.
-        * That way we'll still be able to perform early firmware startup
-        * debugging ...  If the request to get the Firmware's Device Log
-        * parameters fails, we'll live so we don't make that a fatal error.
-        */
-       memset(&devlog_cmd, 0, sizeof(devlog_cmd));
-       devlog_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_DEVLOG_CMD) |
-                                      FW_CMD_REQUEST_F | FW_CMD_READ_F);
-       devlog_cmd.retval_len16 = htonl(FW_LEN16(devlog_cmd));
-       ret = t4_wr_mbox(adap, adap->mbox, &devlog_cmd, sizeof(devlog_cmd),
-                        &devlog_cmd);
-       if (ret == 0) {
-               devlog_meminfo =
-                       ntohl(devlog_cmd.memtype_devlog_memaddr16_devlog);
-               adap->params.devlog.memtype =
-                       FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(devlog_meminfo);
-               adap->params.devlog.start =
-                       FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(devlog_meminfo) << 4;
-               adap->params.devlog.size = ntohl(devlog_cmd.memsize_devlog);
-       }
-
        /*
         * Find out what ports are available to us.  Note that we need to do
         * this before calling adap_init0_no_config() since it needs nports
@@ -5293,6 +5296,51 @@ static int adap_init0(struct adapter *adap)
        adap->tids.nftids = val[4] - val[3] + 1;
        adap->sge.ingr_start = val[5];
 
+       /* qids (ingress/egress) returned from firmware can be anywhere
+        * in the range from EQ(IQFLINT)_START to EQ(IQFLINT)_END.
+        * Hence driver needs to allocate memory for this range to
+        * store the queue info. Get the highest IQFLINT/EQ index returned
+        * in FW_EQ_*_CMD.alloc command.
+        */
+       params[0] = FW_PARAM_PFVF(EQ_END);
+       params[1] = FW_PARAM_PFVF(IQFLINT_END);
+       ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val);
+       if (ret < 0)
+               goto bye;
+       adap->sge.egr_sz = val[0] - adap->sge.egr_start + 1;
+       adap->sge.ingr_sz = val[1] - adap->sge.ingr_start + 1;
+
+       adap->sge.egr_map = kcalloc(adap->sge.egr_sz,
+                                   sizeof(*adap->sge.egr_map), GFP_KERNEL);
+       if (!adap->sge.egr_map) {
+               ret = -ENOMEM;
+               goto bye;
+       }
+
+       adap->sge.ingr_map = kcalloc(adap->sge.ingr_sz,
+                                    sizeof(*adap->sge.ingr_map), GFP_KERNEL);
+       if (!adap->sge.ingr_map) {
+               ret = -ENOMEM;
+               goto bye;
+       }
+
+       /* Allocate the memory for the vaious egress queue bitmaps
+        * ie starving_fl and txq_maperr.
+        */
+       adap->sge.starving_fl = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz),
+                                       sizeof(long), GFP_KERNEL);
+       if (!adap->sge.starving_fl) {
+               ret = -ENOMEM;
+               goto bye;
+       }
+
+       adap->sge.txq_maperr = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz),
+                                      sizeof(long), GFP_KERNEL);
+       if (!adap->sge.txq_maperr) {
+               ret = -ENOMEM;
+               goto bye;
+       }
+
        params[0] = FW_PARAM_PFVF(CLIP_START);
        params[1] = FW_PARAM_PFVF(CLIP_END);
        ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val);
@@ -5501,6 +5549,10 @@ static int adap_init0(struct adapter *adap)
         * happened to HW/FW, stop issuing commands.
         */
 bye:
+       kfree(adap->sge.egr_map);
+       kfree(adap->sge.ingr_map);
+       kfree(adap->sge.starving_fl);
+       kfree(adap->sge.txq_maperr);
        if (ret != -ETIMEDOUT && ret != -EIO)
                t4_fw_bye(adap, adap->mbox);
        return ret;
@@ -5528,6 +5580,7 @@ static pci_ers_result_t eeh_err_detected(struct pci_dev *pdev,
                netif_carrier_off(dev);
        }
        spin_unlock(&adap->stats_lock);
+       disable_interrupts(adap);
        if (adap->flags & FULL_INIT_DONE)
                cxgb_down(adap);
        rtnl_unlock();
@@ -5912,6 +5965,10 @@ static void free_some_resources(struct adapter *adapter)
 
        t4_free_mem(adapter->l2t);
        t4_free_mem(adapter->tids.tid_tab);
+       kfree(adapter->sge.egr_map);
+       kfree(adapter->sge.ingr_map);
+       kfree(adapter->sge.starving_fl);
+       kfree(adapter->sge.txq_maperr);
        disable_msi(adapter);
 
        for_each_port(adapter, i)
@@ -6237,6 +6294,8 @@ static void remove_one(struct pci_dev *pdev)
                if (is_offload(adapter))
                        detach_ulds(adapter);
 
+               disable_interrupts(adapter);
+
                for_each_port(adapter, i)
                        if (adapter->port[i]->reg_state == NETREG_REGISTERED)
                                unregister_netdev(adapter->port[i]);
index b4b9f6048fe730dc1287a648a5e61c7f2d92dd7d..b688b32c21fe530aa0cd48b61323bca3ed269b53 100644 (file)
@@ -2171,7 +2171,7 @@ static void sge_rx_timer_cb(unsigned long data)
        struct adapter *adap = (struct adapter *)data;
        struct sge *s = &adap->sge;
 
-       for (i = 0; i < ARRAY_SIZE(s->starving_fl); i++)
+       for (i = 0; i < BITS_TO_LONGS(s->egr_sz); i++)
                for (m = s->starving_fl[i]; m; m &= m - 1) {
                        struct sge_eth_rxq *rxq;
                        unsigned int id = __ffs(m) + i * BITS_PER_LONG;
@@ -2259,7 +2259,7 @@ static void sge_tx_timer_cb(unsigned long data)
        struct adapter *adap = (struct adapter *)data;
        struct sge *s = &adap->sge;
 
-       for (i = 0; i < ARRAY_SIZE(s->txq_maperr); i++)
+       for (i = 0; i < BITS_TO_LONGS(s->egr_sz); i++)
                for (m = s->txq_maperr[i]; m; m &= m - 1) {
                        unsigned long id = __ffs(m) + i * BITS_PER_LONG;
                        struct sge_ofld_txq *txq = s->egr_map[id];
@@ -2741,7 +2741,8 @@ void t4_free_sge_resources(struct adapter *adap)
                free_rspq_fl(adap, &adap->sge.intrq, NULL);
 
        /* clear the reverse egress queue map */
-       memset(adap->sge.egr_map, 0, sizeof(adap->sge.egr_map));
+       memset(adap->sge.egr_map, 0,
+              adap->sge.egr_sz * sizeof(*adap->sge.egr_map));
 }
 
 void t4_sge_start(struct adapter *adap)
index 1abdfa123c6cf8d42a4788400539b40b05ed84eb..ee394dc68303851153a3598fe4455cec972597d9 100644 (file)
@@ -4458,6 +4458,59 @@ int cxgb4_t4_bar2_sge_qregs(struct adapter *adapter,
        return 0;
 }
 
+/**
+ *     t4_init_devlog_params - initialize adapter->params.devlog
+ *     @adap: the adapter
+ *
+ *     Initialize various fields of the adapter's Firmware Device Log
+ *     Parameters structure.
+ */
+int t4_init_devlog_params(struct adapter *adap)
+{
+       struct devlog_params *dparams = &adap->params.devlog;
+       u32 pf_dparams;
+       unsigned int devlog_meminfo;
+       struct fw_devlog_cmd devlog_cmd;
+       int ret;
+
+       /* If we're dealing with newer firmware, the Device Log Paramerters
+        * are stored in a designated register which allows us to access the
+        * Device Log even if we can't talk to the firmware.
+        */
+       pf_dparams =
+               t4_read_reg(adap, PCIE_FW_REG(PCIE_FW_PF_A, PCIE_FW_PF_DEVLOG));
+       if (pf_dparams) {
+               unsigned int nentries, nentries128;
+
+               dparams->memtype = PCIE_FW_PF_DEVLOG_MEMTYPE_G(pf_dparams);
+               dparams->start = PCIE_FW_PF_DEVLOG_ADDR16_G(pf_dparams) << 4;
+
+               nentries128 = PCIE_FW_PF_DEVLOG_NENTRIES128_G(pf_dparams);
+               nentries = (nentries128 + 1) * 128;
+               dparams->size = nentries * sizeof(struct fw_devlog_e);
+
+               return 0;
+       }
+
+       /* Otherwise, ask the firmware for it's Device Log Parameters.
+        */
+       memset(&devlog_cmd, 0, sizeof(devlog_cmd));
+       devlog_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_DEVLOG_CMD) |
+                                      FW_CMD_REQUEST_F | FW_CMD_READ_F);
+       devlog_cmd.retval_len16 = htonl(FW_LEN16(devlog_cmd));
+       ret = t4_wr_mbox(adap, adap->mbox, &devlog_cmd, sizeof(devlog_cmd),
+                        &devlog_cmd);
+       if (ret)
+               return ret;
+
+       devlog_meminfo = ntohl(devlog_cmd.memtype_devlog_memaddr16_devlog);
+       dparams->memtype = FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(devlog_meminfo);
+       dparams->start = FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(devlog_meminfo) << 4;
+       dparams->size = ntohl(devlog_cmd.memsize_devlog);
+
+       return 0;
+}
+
 /**
  *     t4_init_sge_params - initialize adap->params.sge
  *     @adapter: the adapter
index 231a725f6d5d1679c4d6b07ff6694ac387f0b66a..326674b19983825af5631993b4427e0132ed6ba6 100644 (file)
@@ -63,6 +63,8 @@
 #define MC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4)
 #define EDC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4)
 
+#define PCIE_FW_REG(reg_addr, idx) ((reg_addr) + (idx) * 4)
+
 #define SGE_PF_KDOORBELL_A 0x0
 
 #define QID_S    15
 #define PFNUM_V(x) ((x) << PFNUM_S)
 
 #define PCIE_FW_A 0x30b8
+#define PCIE_FW_PF_A 0x30bc
 
 #define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS_A 0x5908
 
index 9b353a88cbdab13a7ce85456e393edf197dd1740..a4a19e0ec7f5d76590f0e73641d5e03afbcde43a 100644 (file)
@@ -101,7 +101,7 @@ enum fw_wr_opcodes {
        FW_RI_BIND_MW_WR               = 0x18,
        FW_RI_FR_NSMR_WR               = 0x19,
        FW_RI_INV_LSTAG_WR             = 0x1a,
-       FW_LASTC2E_WR                  = 0x40
+       FW_LASTC2E_WR                  = 0x70
 };
 
 struct fw_wr_hdr {
@@ -993,6 +993,7 @@ enum fw_memtype_cf {
        FW_MEMTYPE_CF_EXTMEM            = 0x2,
        FW_MEMTYPE_CF_FLASH             = 0x4,
        FW_MEMTYPE_CF_INTERNAL          = 0x5,
+       FW_MEMTYPE_CF_EXTMEM1           = 0x6,
 };
 
 struct fw_caps_config_cmd {
@@ -1035,6 +1036,7 @@ enum fw_params_mnem {
        FW_PARAMS_MNEM_PFVF             = 2,    /* function params */
        FW_PARAMS_MNEM_REG              = 3,    /* limited register access */
        FW_PARAMS_MNEM_DMAQ             = 4,    /* dma queue params */
+       FW_PARAMS_MNEM_CHNET            = 5,    /* chnet params */
        FW_PARAMS_MNEM_LAST
 };
 
@@ -3102,7 +3104,8 @@ enum fw_devlog_facility {
        FW_DEVLOG_FACILITY_FCOE         = 0x2E,
        FW_DEVLOG_FACILITY_FOISCSI      = 0x30,
        FW_DEVLOG_FACILITY_FOFCOE       = 0x32,
-       FW_DEVLOG_FACILITY_MAX          = 0x32,
+       FW_DEVLOG_FACILITY_CHNET        = 0x34,
+       FW_DEVLOG_FACILITY_MAX          = 0x34,
 };
 
 /* log message format */
@@ -3139,4 +3142,36 @@ struct fw_devlog_cmd {
        (((x) >> FW_DEVLOG_CMD_MEMADDR16_DEVLOG_S) & \
         FW_DEVLOG_CMD_MEMADDR16_DEVLOG_M)
 
+/* P C I E   F W   P F 7   R E G I S T E R */
+
+/* PF7 stores the Firmware Device Log parameters which allows Host Drivers to
+ * access the "devlog" which needing to contact firmware.  The encoding is
+ * mostly the same as that returned by the DEVLOG command except for the size
+ * which is encoded as the number of entries in multiples-1 of 128 here rather
+ * than the memory size as is done in the DEVLOG command.  Thus, 0 means 128
+ * and 15 means 2048.  This of course in turn constrains the allowed values
+ * for the devlog size ...
+ */
+#define PCIE_FW_PF_DEVLOG              7
+
+#define PCIE_FW_PF_DEVLOG_NENTRIES128_S        28
+#define PCIE_FW_PF_DEVLOG_NENTRIES128_M        0xf
+#define PCIE_FW_PF_DEVLOG_NENTRIES128_V(x) \
+       ((x) << PCIE_FW_PF_DEVLOG_NENTRIES128_S)
+#define PCIE_FW_PF_DEVLOG_NENTRIES128_G(x) \
+       (((x) >> PCIE_FW_PF_DEVLOG_NENTRIES128_S) & \
+        PCIE_FW_PF_DEVLOG_NENTRIES128_M)
+
+#define PCIE_FW_PF_DEVLOG_ADDR16_S     4
+#define PCIE_FW_PF_DEVLOG_ADDR16_M     0xffffff
+#define PCIE_FW_PF_DEVLOG_ADDR16_V(x)  ((x) << PCIE_FW_PF_DEVLOG_ADDR16_S)
+#define PCIE_FW_PF_DEVLOG_ADDR16_G(x) \
+       (((x) >> PCIE_FW_PF_DEVLOG_ADDR16_S) & PCIE_FW_PF_DEVLOG_ADDR16_M)
+
+#define PCIE_FW_PF_DEVLOG_MEMTYPE_S    0
+#define PCIE_FW_PF_DEVLOG_MEMTYPE_M    0xf
+#define PCIE_FW_PF_DEVLOG_MEMTYPE_V(x) ((x) << PCIE_FW_PF_DEVLOG_MEMTYPE_S)
+#define PCIE_FW_PF_DEVLOG_MEMTYPE_G(x) \
+       (((x) >> PCIE_FW_PF_DEVLOG_MEMTYPE_S) & PCIE_FW_PF_DEVLOG_MEMTYPE_M)
+
 #endif /* _T4FW_INTERFACE_H_ */
index e2bd3f74785851d0db24c282f5a497972bcaf20f..b9d1cbac0eee3c97e76cff147df732601b83f714 100644 (file)
 #define __T4FW_VERSION_H__
 
 #define T4FW_VERSION_MAJOR 0x01
-#define T4FW_VERSION_MINOR 0x0C
-#define T4FW_VERSION_MICRO 0x19
+#define T4FW_VERSION_MINOR 0x0D
+#define T4FW_VERSION_MICRO 0x20
 #define T4FW_VERSION_BUILD 0x00
 
 #define T5FW_VERSION_MAJOR 0x01
-#define T5FW_VERSION_MINOR 0x0C
-#define T5FW_VERSION_MICRO 0x19
+#define T5FW_VERSION_MINOR 0x0D
+#define T5FW_VERSION_MICRO 0x20
 #define T5FW_VERSION_BUILD 0x00
 
 #endif
index 0545f0de1c52be282af53d6a5f03916f93ad7013..e0d711071afb7d6d80763666141477fb3dc4c479 100644 (file)
@@ -1004,7 +1004,7 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq,
                                              ? (tq->pidx - 1)
                                              : (tq->size - 1));
                        __be64 *src = (__be64 *)&tq->desc[index];
-                       __be64 __iomem *dst = (__be64 *)(tq->bar2_addr +
+                       __be64 __iomem *dst = (__be64 __iomem *)(tq->bar2_addr +
                                                         SGE_UDB_WCDOORBELL);
                        unsigned int count = EQ_UNIT / sizeof(__be64);
 
@@ -1018,7 +1018,11 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq,
                         * DMA.
                         */
                        while (count) {
-                               writeq(*src, dst);
+                               /* the (__force u64) is because the compiler
+                                * doesn't understand the endian swizzling
+                                * going on
+                                */
+                               writeq((__force u64)*src, dst);
                                src++;
                                dst++;
                                count--;
@@ -1252,8 +1256,8 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
        BUG_ON(DIV_ROUND_UP(ETHTXQ_MAX_HDR, TXD_PER_EQ_UNIT) > 1);
        wr = (void *)&txq->q.desc[txq->q.pidx];
        wr->equiq_to_len16 = cpu_to_be32(wr_mid);
-       wr->r3[0] = cpu_to_be64(0);
-       wr->r3[1] = cpu_to_be64(0);
+       wr->r3[0] = cpu_to_be32(0);
+       wr->r3[1] = cpu_to_be32(0);
        skb_copy_from_linear_data(skb, (void *)wr->ethmacdst, fw_hdr_copy_len);
        end = (u64 *)wr + flits;
 
index 1b5506df35b15ab74eaf1ecea220da4ad6278a3f..280b4a21584934f56fbcc24399dfd0cf5feb694e 100644 (file)
@@ -210,10 +210,10 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
 
                        if (rpl) {
                                /* request bit in high-order BE word */
-                               WARN_ON((be32_to_cpu(*(const u32 *)cmd)
+                               WARN_ON((be32_to_cpu(*(const __be32 *)cmd)
                                         & FW_CMD_REQUEST_F) == 0);
                                get_mbox_rpl(adapter, rpl, size, mbox_data);
-                               WARN_ON((be32_to_cpu(*(u32 *)rpl)
+                               WARN_ON((be32_to_cpu(*(__be32 *)rpl)
                                         & FW_CMD_REQUEST_F) != 0);
                        }
                        t4_write_reg(adapter, mbox_ctl,
@@ -484,7 +484,7 @@ int t4_bar2_sge_qregs(struct adapter *adapter,
         *  o The BAR2 Queue ID.
         *  o The BAR2 Queue ID Offset into the BAR2 page.
         */
-       bar2_page_offset = ((qid >> qpp_shift) << page_shift);
+       bar2_page_offset = ((u64)(qid >> qpp_shift) << page_shift);
        bar2_qid = qid & qpp_mask;
        bar2_qid_offset = bar2_qid * SGE_UDB_SIZE;
 
index 78e1ce09b1ab1deadad177472593e020a8f9d3c2..f6a3a7abd468e1f25fd4c33e874a38f0c85bc4dd 100644 (file)
@@ -1954,6 +1954,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
        struct fec_enet_private *fep = netdev_priv(ndev);
        struct device_node *node;
        int err = -ENXIO, i;
+       u32 mii_speed, holdtime;
 
        /*
         * The i.MX28 dual fec interfaces are not equal.
@@ -1991,10 +1992,33 @@ static int fec_enet_mii_init(struct platform_device *pdev)
         * Reference Manual has an error on this, and gets fixed on i.MX6Q
         * document.
         */
-       fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000);
+       mii_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000);
        if (fep->quirks & FEC_QUIRK_ENET_MAC)
-               fep->phy_speed--;
-       fep->phy_speed <<= 1;
+               mii_speed--;
+       if (mii_speed > 63) {
+               dev_err(&pdev->dev,
+                       "fec clock (%lu) to fast to get right mii speed\n",
+                       clk_get_rate(fep->clk_ipg));
+               err = -EINVAL;
+               goto err_out;
+       }
+
+       /*
+        * The i.MX28 and i.MX6 types have another filed in the MSCR (aka
+        * MII_SPEED) register that defines the MDIO output hold time. Earlier
+        * versions are RAZ there, so just ignore the difference and write the
+        * register always.
+        * The minimal hold time according to IEE802.3 (clause 22) is 10 ns.
+        * HOLDTIME + 1 is the number of clk cycles the fec is holding the
+        * output.
+        * The HOLDTIME bitfield takes values between 0 and 7 (inclusive).
+        * Given that ceil(clkrate / 5000000) <= 64, the calculation for
+        * holdtime cannot result in a value greater than 3.
+        */
+       holdtime = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 100000000) - 1;
+
+       fep->phy_speed = mii_speed << 1 | holdtime << 8;
+
        writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
 
        fep->mii_bus = mdiobus_alloc();
index 357e8b576905a4a61c312e6c9736c087b706b69d..56b774d3a13d4c3856ad01fff0ebe67c128e4f65 100644 (file)
@@ -3893,6 +3893,9 @@ static int ucc_geth_probe(struct platform_device* ofdev)
        ugeth->phy_interface = phy_interface;
        ugeth->max_speed = max_speed;
 
+       /* Carrier starts down, phylib will bring it up */
+       netif_carrier_off(dev);
+
        err = register_netdev(dev);
        if (err) {
                if (netif_msg_probe(ugeth))
index 96208f17bb53be6240ae9e8d0cd30cc09041163e..2db653225a0e7713b21ecf3e80996eccf1a8a7d1 100644 (file)
@@ -2658,16 +2658,11 @@ static int mvneta_stop(struct net_device *dev)
 static int mvneta_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
        struct mvneta_port *pp = netdev_priv(dev);
-       int ret;
 
        if (!pp->phy_dev)
                return -ENOTSUPP;
 
-       ret = phy_mii_ioctl(pp->phy_dev, ifr, cmd);
-       if (!ret)
-               mvneta_adjust_link(dev);
-
-       return ret;
+       return phy_mii_ioctl(pp->phy_dev, ifr, cmd);
 }
 
 /* Ethtool methods */
index a681d7c0bb9f066f8d48ed068f68f0001dad8d0f..546ca4226916dbf2261525c12dc087ba35c7f4d7 100644 (file)
@@ -724,7 +724,8 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
                 * on the host, we deprecate the error message for this
                 * specific command/input_mod/opcode_mod/fw-status to be debug.
                 */
-               if (op == MLX4_CMD_SET_PORT && in_modifier == 1 &&
+               if (op == MLX4_CMD_SET_PORT &&
+                   (in_modifier == 1 || in_modifier == 2) &&
                    op_modifier == 0 && context->fw_status == CMD_STAT_BAD_SIZE)
                        mlx4_dbg(dev, "command 0x%x failed: fw status = 0x%x\n",
                                 op, context->fw_status);
@@ -1993,7 +1994,6 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
                        goto reset_slave;
                slave_state[slave].vhcr_dma = ((u64) param) << 48;
                priv->mfunc.master.slave_state[slave].cookie = 0;
-               mutex_init(&priv->mfunc.master.gen_eqe_mutex[slave]);
                break;
        case MLX4_COMM_CMD_VHCR1:
                if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR0)
@@ -2225,6 +2225,7 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
                for (i = 0; i < dev->num_slaves; ++i) {
                        s_state = &priv->mfunc.master.slave_state[i];
                        s_state->last_cmd = MLX4_COMM_CMD_RESET;
+                       mutex_init(&priv->mfunc.master.gen_eqe_mutex[i]);
                        for (j = 0; j < MLX4_EVENT_TYPES_NUM; ++j)
                                s_state->event_eq[j].eqn = -1;
                        __raw_writel((__force u32) 0,
index ebce5bb24df98b77eec38a1fc6c720987768934b..3485acf03014c7e4df64fa94a770fce00abe5a35 100644 (file)
@@ -2805,13 +2805,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        netif_carrier_off(dev);
        mlx4_en_set_default_moderation(priv);
 
-       err = register_netdev(dev);
-       if (err) {
-               en_err(priv, "Netdev registration failed for port %d\n", port);
-               goto out;
-       }
-       priv->registered = 1;
-
        en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num);
        en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num);
 
@@ -2853,6 +2846,14 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 
        mlx4_set_stats_bitmap(mdev->dev, &priv->stats_bitmap);
 
+       err = register_netdev(dev);
+       if (err) {
+               en_err(priv, "Netdev registration failed for port %d\n", port);
+               goto out;
+       }
+
+       priv->registered = 1;
+
        return 0;
 
 out:
index 264bc15c1ff212ad649c3547c8a8ffc0b2c22e43..6e70ffee8e87ee2fa9957adeb5994ca346bf155b 100644 (file)
@@ -153,12 +153,10 @@ void mlx4_gen_slave_eqe(struct work_struct *work)
 
                /* All active slaves need to receive the event */
                if (slave == ALL_SLAVES) {
-                       for (i = 0; i < dev->num_slaves; i++) {
-                               if (i != dev->caps.function &&
-                                   master->slave_state[i].active)
-                                       if (mlx4_GEN_EQE(dev, i, eqe))
-                                               mlx4_warn(dev, "Failed to generate event for slave %d\n",
-                                                         i);
+                       for (i = 0; i <= dev->persist->num_vfs; i++) {
+                               if (mlx4_GEN_EQE(dev, i, eqe))
+                                       mlx4_warn(dev, "Failed to generate event for slave %d\n",
+                                                 i);
                        }
                } else {
                        if (mlx4_GEN_EQE(dev, slave, eqe))
@@ -203,13 +201,11 @@ static void mlx4_slave_event(struct mlx4_dev *dev, int slave,
                             struct mlx4_eqe *eqe)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
-       struct mlx4_slave_state *s_slave =
-               &priv->mfunc.master.slave_state[slave];
 
-       if (!s_slave->active) {
-               /*mlx4_warn(dev, "Trying to pass event to inactive slave\n");*/
+       if (slave < 0 || slave > dev->persist->num_vfs ||
+           slave == dev->caps.function ||
+           !priv->mfunc.master.slave_state[slave].active)
                return;
-       }
 
        slave_event(dev, slave, eqe);
 }
index d97ca88c55b59e039af66991e4ad413f82984158..6e413ac4e94011c4ea85993b8471d5adfc84d5d3 100644 (file)
@@ -3095,6 +3095,12 @@ int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe)
        if (!priv->mfunc.master.slave_state)
                return -EINVAL;
 
+       /* check for slave valid, slave not PF, and slave active */
+       if (slave < 0 || slave > dev->persist->num_vfs ||
+           slave == dev->caps.function ||
+           !priv->mfunc.master.slave_state[slave].active)
+               return 0;
+
        event_eq = &priv->mfunc.master.slave_state[slave].event_eq[eqe->type];
 
        /* Create the event only if the slave is registered */
index 9fb6948e14c64ef424c032811364aaefc608d4cb..5cecec282aba8b471b60b91af594ba6374edcda7 100644 (file)
@@ -4468,10 +4468,16 @@ static int rocker_port_master_changed(struct net_device *dev)
        struct net_device *master = netdev_master_upper_dev_get(dev);
        int err = 0;
 
+       /* There are currently three cases handled here:
+        * 1. Joining a bridge
+        * 2. Leaving a previously joined bridge
+        * 3. Other, e.g. being added to or removed from a bond or openvswitch,
+        *    in which case nothing is done
+        */
        if (master && master->rtnl_link_ops &&
            !strcmp(master->rtnl_link_ops->kind, "bridge"))
                err = rocker_port_bridge_join(rocker_port, master);
-       else
+       else if (rocker_port_is_bridged(rocker_port))
                err = rocker_port_bridge_leave(rocker_port);
 
        return err;
index 924ea98bd5311b1c7197a9fe4e9b475b095069ce..54549a6223dd2f47f493ae112a06f12f3337120f 100644 (file)
@@ -114,7 +114,9 @@ unsigned int ipvlan_mac_hash(const unsigned char *addr);
 rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb);
 int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev);
 void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr);
-bool ipvlan_addr_busy(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6);
+struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
+                                  const void *iaddr, bool is_v6);
+bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6);
 struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port,
                                        const void *iaddr, bool is_v6);
 void ipvlan_ht_addr_del(struct ipvl_addr *addr, bool sync);
index 2a175006028b347efe1fbe6d145f311f78c80bd7..b7877a194cfe430469af8031c58efdf307eafc4f 100644 (file)
@@ -81,19 +81,20 @@ void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr)
        hash = (addr->atype == IPVL_IPV6) ?
               ipvlan_get_v6_hash(&addr->ip6addr) :
               ipvlan_get_v4_hash(&addr->ip4addr);
-       hlist_add_head_rcu(&addr->hlnode, &port->hlhead[hash]);
+       if (hlist_unhashed(&addr->hlnode))
+               hlist_add_head_rcu(&addr->hlnode, &port->hlhead[hash]);
 }
 
 void ipvlan_ht_addr_del(struct ipvl_addr *addr, bool sync)
 {
-       hlist_del_rcu(&addr->hlnode);
+       hlist_del_init_rcu(&addr->hlnode);
        if (sync)
                synchronize_rcu();
 }
 
-bool ipvlan_addr_busy(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6)
+struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
+                                  const void *iaddr, bool is_v6)
 {
-       struct ipvl_port *port = ipvlan->port;
        struct ipvl_addr *addr;
 
        list_for_each_entry(addr, &ipvlan->addrs, anode) {
@@ -101,12 +102,21 @@ bool ipvlan_addr_busy(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6)
                    ipv6_addr_equal(&addr->ip6addr, iaddr)) ||
                    (!is_v6 && addr->atype == IPVL_IPV4 &&
                    addr->ip4addr.s_addr == ((struct in_addr *)iaddr)->s_addr))
-                       return true;
+                       return addr;
        }
+       return NULL;
+}
+
+bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6)
+{
+       struct ipvl_dev *ipvlan;
 
-       if (ipvlan_ht_addr_lookup(port, iaddr, is_v6))
-               return true;
+       ASSERT_RTNL();
 
+       list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
+               if (ipvlan_find_addr(ipvlan, iaddr, is_v6))
+                       return true;
+       }
        return false;
 }
 
@@ -192,7 +202,8 @@ static void ipvlan_multicast_frame(struct ipvl_port *port, struct sk_buff *skb,
        if (skb->protocol == htons(ETH_P_PAUSE))
                return;
 
-       list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(ipvlan, &port->ipvlans, pnode) {
                if (local && (ipvlan == in_dev))
                        continue;
 
@@ -219,6 +230,7 @@ static void ipvlan_multicast_frame(struct ipvl_port *port, struct sk_buff *skb,
 mcast_acct:
                ipvlan_count_rx(ipvlan, len, ret == NET_RX_SUCCESS, true);
        }
+       rcu_read_unlock();
 
        /* Locally generated? ...Forward a copy to the main-device as
         * well. On the RX side we'll ignore it (wont give it to any
index 4f4099d5603d0b64f2a15b66e86dbee90260cead..4fa14208d79931df1b5d8707744e93043b951424 100644 (file)
@@ -505,7 +505,7 @@ static void ipvlan_link_delete(struct net_device *dev, struct list_head *head)
        if (ipvlan->ipv6cnt > 0 || ipvlan->ipv4cnt > 0) {
                list_for_each_entry_safe(addr, next, &ipvlan->addrs, anode) {
                        ipvlan_ht_addr_del(addr, !dev->dismantle);
-                       list_del_rcu(&addr->anode);
+                       list_del(&addr->anode);
                }
        }
        list_del_rcu(&ipvlan->pnode);
@@ -607,7 +607,7 @@ static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
 {
        struct ipvl_addr *addr;
 
-       if (ipvlan_addr_busy(ipvlan, ip6_addr, true)) {
+       if (ipvlan_addr_busy(ipvlan->port, ip6_addr, true)) {
                netif_err(ipvlan, ifup, ipvlan->dev,
                          "Failed to add IPv6=%pI6c addr for %s intf\n",
                          ip6_addr, ipvlan->dev->name);
@@ -620,9 +620,13 @@ static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
        addr->master = ipvlan;
        memcpy(&addr->ip6addr, ip6_addr, sizeof(struct in6_addr));
        addr->atype = IPVL_IPV6;
-       list_add_tail_rcu(&addr->anode, &ipvlan->addrs);
+       list_add_tail(&addr->anode, &ipvlan->addrs);
        ipvlan->ipv6cnt++;
-       ipvlan_ht_addr_add(ipvlan, addr);
+       /* If the interface is not up, the address will be added to the hash
+        * list by ipvlan_open.
+        */
+       if (netif_running(ipvlan->dev))
+               ipvlan_ht_addr_add(ipvlan, addr);
 
        return 0;
 }
@@ -631,12 +635,12 @@ static void ipvlan_del_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
 {
        struct ipvl_addr *addr;
 
-       addr = ipvlan_ht_addr_lookup(ipvlan->port, ip6_addr, true);
+       addr = ipvlan_find_addr(ipvlan, ip6_addr, true);
        if (!addr)
                return;
 
        ipvlan_ht_addr_del(addr, true);
-       list_del_rcu(&addr->anode);
+       list_del(&addr->anode);
        ipvlan->ipv6cnt--;
        WARN_ON(ipvlan->ipv6cnt < 0);
        kfree_rcu(addr, rcu);
@@ -675,7 +679,7 @@ static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
 {
        struct ipvl_addr *addr;
 
-       if (ipvlan_addr_busy(ipvlan, ip4_addr, false)) {
+       if (ipvlan_addr_busy(ipvlan->port, ip4_addr, false)) {
                netif_err(ipvlan, ifup, ipvlan->dev,
                          "Failed to add IPv4=%pI4 on %s intf.\n",
                          ip4_addr, ipvlan->dev->name);
@@ -688,9 +692,13 @@ static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
        addr->master = ipvlan;
        memcpy(&addr->ip4addr, ip4_addr, sizeof(struct in_addr));
        addr->atype = IPVL_IPV4;
-       list_add_tail_rcu(&addr->anode, &ipvlan->addrs);
+       list_add_tail(&addr->anode, &ipvlan->addrs);
        ipvlan->ipv4cnt++;
-       ipvlan_ht_addr_add(ipvlan, addr);
+       /* If the interface is not up, the address will be added to the hash
+        * list by ipvlan_open.
+        */
+       if (netif_running(ipvlan->dev))
+               ipvlan_ht_addr_add(ipvlan, addr);
        ipvlan_set_broadcast_mac_filter(ipvlan, true);
 
        return 0;
@@ -700,12 +708,12 @@ static void ipvlan_del_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
 {
        struct ipvl_addr *addr;
 
-       addr = ipvlan_ht_addr_lookup(ipvlan->port, ip4_addr, false);
+       addr = ipvlan_find_addr(ipvlan, ip4_addr, false);
        if (!addr)
                return;
 
        ipvlan_ht_addr_del(addr, true);
-       list_del_rcu(&addr->anode);
+       list_del(&addr->anode);
        ipvlan->ipv4cnt--;
        WARN_ON(ipvlan->ipv4cnt < 0);
        if (!ipvlan->ipv4cnt)
index 5c55f11572baa0a3e0dd3877ae886935cb8a6eb9..75d6f26729a30e34cdaaf8334a9cc0aaa2a01c82 100644 (file)
@@ -188,6 +188,8 @@ struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
                memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
                skb_put(skb, sizeof(padbytes));
        }
+
+       usbnet_set_skb_tx_stats(skb, 1, 0);
        return skb;
 }
 
index 9311a08565bed17cf5082a21b9c6dca7ab02dfe1..4545e78840b0d9dc80ae4392b36cfcf588f17c3a 100644 (file)
@@ -522,6 +522,7 @@ static const struct driver_info wwan_info = {
 #define DELL_VENDOR_ID         0x413C
 #define REALTEK_VENDOR_ID      0x0bda
 #define SAMSUNG_VENDOR_ID      0x04e8
+#define LENOVO_VENDOR_ID       0x17ef
 
 static const struct usb_device_id      products[] = {
 /* BLACKLIST !!
@@ -702,6 +703,13 @@ static const struct usb_device_id  products[] = {
        .driver_info = 0,
 },
 
+/* Lenovo Thinkpad USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */
+{
+       USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x7205, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+       .driver_info = 0,
+},
+
 /* WHITELIST!!!
  *
  * CDC Ether uses two interfaces, not necessarily consecutive.
index 80a844e0ae0383303d8fa4a6d4147fc99337f268..c3e4da9e79ca071a06082e965a3aec5bb206a77e 100644 (file)
@@ -1172,17 +1172,17 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
 
        /* return skb */
        ctx->tx_curr_skb = NULL;
-       dev->net->stats.tx_packets += ctx->tx_curr_frame_num;
 
        /* keep private stats: framing overhead and number of NTBs */
        ctx->tx_overhead += skb_out->len - ctx->tx_curr_frame_payload;
        ctx->tx_ntbs++;
 
-       /* usbnet has already counted all the framing overhead.
+       /* usbnet will count all the framing overhead by default.
         * Adjust the stats so that the tx_bytes counter show real
         * payload data instead.
         */
-       dev->net->stats.tx_bytes -= skb_out->len - ctx->tx_curr_frame_payload;
+       usbnet_set_skb_tx_stats(skb_out, n,
+                               ctx->tx_curr_frame_payload - skb_out->len);
 
        return skb_out;
 
index 438fc6bcaef15538e9c151c46fce08dc67cec1a5..9f7c0ab3b3490b947d161428406612c80dc29360 100644 (file)
@@ -492,6 +492,7 @@ enum rtl8152_flags {
 /* Define these values to match your device */
 #define VENDOR_ID_REALTEK              0x0bda
 #define VENDOR_ID_SAMSUNG              0x04e8
+#define VENDOR_ID_LENOVO               0x17ef
 
 #define MCU_TYPE_PLA                   0x0100
 #define MCU_TYPE_USB                   0x0000
@@ -4037,6 +4038,7 @@ static struct usb_device_id rtl8152_table[] = {
        {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8152)},
        {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)},
        {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)},
+       {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x7205)},
        {}
 };
 
index b94a0fbb8b3b5a74ed466c4d5a66e25f4f2e0edc..953de13267df19d6fcefe60c2008f6222ca5775c 100644 (file)
@@ -144,6 +144,7 @@ static struct sk_buff *sr_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
                skb_put(skb, sizeof(padbytes));
        }
 
+       usbnet_set_skb_tx_stats(skb, 1, 0);
        return skb;
 }
 
index 449835f4331e210daad6c8717430341c1c6996ef..777757ae19732ab10ab2283645464a87a02c7b20 100644 (file)
@@ -1188,8 +1188,7 @@ static void tx_complete (struct urb *urb)
        struct usbnet           *dev = entry->dev;
 
        if (urb->status == 0) {
-               if (!(dev->driver_info->flags & FLAG_MULTI_PACKET))
-                       dev->net->stats.tx_packets++;
+               dev->net->stats.tx_packets += entry->packets;
                dev->net->stats.tx_bytes += entry->length;
        } else {
                dev->net->stats.tx_errors++;
@@ -1347,7 +1346,19 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
                } else
                        urb->transfer_flags |= URB_ZERO_PACKET;
        }
-       entry->length = urb->transfer_buffer_length = length;
+       urb->transfer_buffer_length = length;
+
+       if (info->flags & FLAG_MULTI_PACKET) {
+               /* Driver has set number of packets and a length delta.
+                * Calculate the complete length and ensure that it's
+                * positive.
+                */
+               entry->length += length;
+               if (WARN_ON_ONCE(entry->length <= 0))
+                       entry->length = length;
+       } else {
+               usbnet_set_skb_tx_stats(skb, 1, length);
+       }
 
        spin_lock_irqsave(&dev->txq.lock, flags);
        retval = usb_autopm_get_interface_async(dev->intf);
index cb366adc820b17a667a908d79db82da8519f3783..f50a6bc5d06ee0b2bb3c83c971cd5f1d81afd690 100644 (file)
@@ -219,12 +219,15 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_vif *avp = (void *)vif->drv_priv;
        struct ath_buf *bf = avp->av_bcbuf;
+       struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
 
        ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
                avp->av_bslot);
 
        tasklet_disable(&sc->bcon_tasklet);
 
+       cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
+
        if (bf && bf->bf_mpdu) {
                struct sk_buff *skb = bf->bf_mpdu;
                dma_unmap_single(sc->dev, bf->bf_buf_addr,
@@ -521,8 +524,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc,
        }
 
        if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
-               if ((vif->type != NL80211_IFTYPE_AP) ||
-                   (sc->nbcnvifs > 1)) {
+               if (vif->type != NL80211_IFTYPE_AP) {
                        ath_dbg(common, CONFIG,
                                "An AP interface is already present !\n");
                        return false;
@@ -616,12 +618,14 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
         * enabling/disabling SWBA.
         */
        if (changed & BSS_CHANGED_BEACON_ENABLED) {
-               if (!bss_conf->enable_beacon &&
-                   (sc->nbcnvifs <= 1)) {
-                       cur_conf->enable_beacon = false;
-               } else if (bss_conf->enable_beacon) {
-                       cur_conf->enable_beacon = true;
-                       ath9k_cache_beacon_config(sc, ctx, bss_conf);
+               bool enabled = cur_conf->enable_beacon;
+
+               if (!bss_conf->enable_beacon) {
+                       cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
+               } else {
+                       cur_conf->enable_beacon |= BIT(avp->av_bslot);
+                       if (!enabled)
+                               ath9k_cache_beacon_config(sc, ctx, bss_conf);
                }
        }
 
index 2b79a568e8032c1fbc33a0fb550a5da6140f2865..d23737342f4fe7b311c84a7d556cad6e94ecf1f1 100644 (file)
@@ -54,7 +54,7 @@ struct ath_beacon_config {
        u16 dtim_period;
        u16 bmiss_timeout;
        u8 dtim_count;
-       bool enable_beacon;
+       u8 enable_beacon;
        bool ibss_creator;
        u32 nexttbtt;
        u32 intval;
index 60aa8d71e753fa936909dcc98ef915c2a2208f60..8529014e1a5e1c1b4637abc1625fd177b407f602 100644 (file)
@@ -424,7 +424,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
        ah->power_mode = ATH9K_PM_UNDEFINED;
        ah->htc_reset_init = true;
 
-       ah->tpc_enabled = true;
+       ah->tpc_enabled = false;
 
        ah->ani_function = ATH9K_ANI_ALL;
        if (!AR_SREV_9300_20_OR_LATER(ah))
index defb7a44e0bc1ff554195890dcccc31bfb0c9769..7748a1ccf14fdf4a6b2864441e9b041da35558a6 100644 (file)
@@ -126,7 +126,8 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
        brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan");
        if (drvr->bus_if->wowl_supported)
                brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
-       brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0);
+       if (drvr->bus_if->chip != BRCM_CC_43362_CHIP_ID)
+               brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0);
 
        /* set chip related quirks */
        switch (drvr->bus_if->chip) {
index a6f22c32a27994000f578c2baff08a2f62042aa0..3811878ab9cd2057ad44785c7f3dad5cb5edcf07 100644 (file)
@@ -708,7 +708,6 @@ struct iwl_priv {
        unsigned long reload_jiffies;
        int reload_count;
        bool ucode_loaded;
-       bool init_ucode_run;            /* Don't run init uCode again */
 
        u8 plcp_delta_threshold;
 
index 47e64e8b9517d97dff6b96e544a731d498412ba1..cceb026e0793b45fa418e7c023855d5c0bd23a02 100644 (file)
@@ -1114,16 +1114,17 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        scd_queues &= ~(BIT(IWL_IPAN_CMD_QUEUE_NUM) |
                        BIT(IWL_DEFAULT_CMD_QUEUE_NUM));
 
-       if (vif)
-               scd_queues &= ~BIT(vif->hw_queue[IEEE80211_AC_VO]);
-
-       IWL_DEBUG_TX_QUEUES(priv, "Flushing SCD queues: 0x%x\n", scd_queues);
-       if (iwlagn_txfifo_flush(priv, scd_queues)) {
-               IWL_ERR(priv, "flush request fail\n");
-               goto done;
+       if (drop) {
+               IWL_DEBUG_TX_QUEUES(priv, "Flushing SCD queues: 0x%x\n",
+                                   scd_queues);
+               if (iwlagn_txfifo_flush(priv, scd_queues)) {
+                       IWL_ERR(priv, "flush request fail\n");
+                       goto done;
+               }
        }
+
        IWL_DEBUG_TX_QUEUES(priv, "wait transmit/flush all frames\n");
-       iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff);
+       iwl_trans_wait_tx_queue_empty(priv->trans, scd_queues);
 done:
        mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
index 4dbef7e58c2e3dfba5be41c1f2f4cfe32c04727b..5244e43bfafbc4617720097660ec693f5d30742f 100644 (file)
@@ -418,9 +418,6 @@ int iwl_run_init_ucode(struct iwl_priv *priv)
        if (!priv->fw->img[IWL_UCODE_INIT].sec[0].len)
                return 0;
 
-       if (priv->init_ucode_run)
-               return 0;
-
        iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
                                   calib_complete, ARRAY_SIZE(calib_complete),
                                   iwlagn_wait_calib, priv);
@@ -440,8 +437,6 @@ int iwl_run_init_ucode(struct iwl_priv *priv)
         */
        ret = iwl_wait_notification(&priv->notif_wait, &calib_wait,
                                        UCODE_CALIB_TIMEOUT);
-       if (!ret)
-               priv->init_ucode_run = true;
 
        goto out;
 
index 996e7f16adf9feafc50cb5d56596a2b80e0cafb3..c7154ac42c8c366d093cfb462a46d9ac98c01e02 100644 (file)
@@ -1257,6 +1257,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
                                op->name, err);
 #endif
        }
+       kfree(pieces);
        return;
 
  try_again:
index efa9688a4cf11150f6d1e92c71e0a367d90fea87..078f24cf4af3927c66e2540bc6cc6404d0c36fc7 100644 (file)
@@ -1278,6 +1278,9 @@ static void rs_mac80211_tx_status(void *mvm_r,
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
+       if (!iwl_mvm_sta_from_mac80211(sta)->vif)
+               return;
+
        if (!ieee80211_is_data(hdr->frame_control) ||
            info->flags & IEEE80211_TX_CTL_NO_ACK)
                return;
@@ -2511,6 +2514,14 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct iwl_lq_sta *lq_sta = mvm_sta;
 
+       if (sta && !iwl_mvm_sta_from_mac80211(sta)->vif) {
+               /* if vif isn't initialized mvm doesn't know about
+                * this station, so don't do anything with the it
+                */
+               sta = NULL;
+               mvm_sta = NULL;
+       }
+
        /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */
 
        /* Treat uninitialized rate scaling data same as non-existing. */
@@ -2827,6 +2838,9 @@ static void rs_rate_update(void *mvm_r,
                        (struct iwl_op_mode *)mvm_r;
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
 
+       if (!iwl_mvm_sta_from_mac80211(sta)->vif)
+               return;
+
        /* Stop any ongoing aggregations as rs starts off assuming no agg */
        for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
                ieee80211_stop_tx_ba_session(sta, tid);
@@ -3587,9 +3601,15 @@ static ssize_t iwl_dbgfs_ss_force_write(struct iwl_lq_sta *lq_sta, char *buf,
 
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(ss_force, 32);
 
-static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir)
+static void rs_add_debugfs(void *mvm, void *priv_sta, struct dentry *dir)
 {
-       struct iwl_lq_sta *lq_sta = mvm_sta;
+       struct iwl_lq_sta *lq_sta = priv_sta;
+       struct iwl_mvm_sta *mvmsta;
+
+       mvmsta = container_of(lq_sta, struct iwl_mvm_sta, lq_sta);
+
+       if (!mvmsta->vif)
+               return;
 
        debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir,
                            lq_sta, &rs_sta_dbgfs_scale_table_ops);
index f8d6f306dd76d276b82056c9fb1a74956e78ac3c..4b81c0bf63b0a86173afde87ef2822c0dfa8860f 100644 (file)
@@ -197,6 +197,8 @@ iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm,
                             struct iwl_time_event_notif *notif)
 {
        if (!le32_to_cpu(notif->status)) {
+               if (te_data->vif->type == NL80211_IFTYPE_STATION)
+                       ieee80211_connection_loss(te_data->vif);
                IWL_DEBUG_TE(mvm, "CSA time event failed to start\n");
                iwl_mvm_te_clear_data(mvm, te_data);
                return;
index 07304e1fd64aa70b41d4c9a18762b48924a6f250..96a05406babf864fb0ff463e9b87dc4c27ba5299 100644 (file)
@@ -949,8 +949,10 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
        mvmsta = iwl_mvm_sta_from_mac80211(sta);
        tid_data = &mvmsta->tid_data[tid];
 
-       if (WARN_ONCE(tid_data->txq_id != scd_flow, "Q %d, tid %d, flow %d",
-                     tid_data->txq_id, tid, scd_flow)) {
+       if (tid_data->txq_id != scd_flow) {
+               IWL_ERR(mvm,
+                       "invalid BA notification: Q %d, tid %d, flow %d\n",
+                       tid_data->txq_id, tid, scd_flow);
                rcu_read_unlock();
                return 0;
        }
index dbd6bcf5220563c03727bccde83083032b977ff8..686dd301cd536b68d616ea0507a3e1742e12240c 100644 (file)
@@ -368,10 +368,12 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
 /* 3165 Series */
        {IWL_PCI_DEVICE(0x3165, 0x4010, iwl3165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x3165, 0x4012, iwl3165_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x3165, 0x4110, iwl3165_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x3165, 0x4210, iwl3165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x3165, 0x4410, iwl3165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x3165, 0x4510, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3165, 0x4110, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3166, 0x4310, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3166, 0x4210, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3165, 0x8010, iwl3165_2ac_cfg)},
 
 /* 7265 Series */
        {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)},
index a62170ea04818e37790eeec99fc2047e255b030f..8c45cf44ce24bac6393902ae2daf708b0ce11e6a 100644 (file)
@@ -1124,12 +1124,22 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
        /*This is for new trx flow*/
        struct rtl_tx_buffer_desc *pbuffer_desc = NULL;
        u8 temp_one = 1;
+       u8 *entry;
 
        memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
        ring = &rtlpci->tx_ring[BEACON_QUEUE];
        pskb = __skb_dequeue(&ring->queue);
-       if (pskb)
+       if (rtlpriv->use_new_trx_flow)
+               entry = (u8 *)(&ring->buffer_desc[ring->idx]);
+       else
+               entry = (u8 *)(&ring->desc[ring->idx]);
+       if (pskb) {
+               pci_unmap_single(rtlpci->pdev,
+                                rtlpriv->cfg->ops->get_desc(
+                                (u8 *)entry, true, HW_DESC_TXBUFF_ADDR),
+                                pskb->len, PCI_DMA_TODEVICE);
                kfree_skb(pskb);
+       }
 
        /*NB: the beacon data buffer must be 32-bit aligned. */
        pskb = ieee80211_beacon_get(hw, mac->vif);
index e9b960f0ff32c8af2ff404a138780ff751bf4572..720aaf6313d296bec9b9a4826f1240b0eb4c0940 100644 (file)
@@ -1008,8 +1008,7 @@ err:
 
 static int xennet_change_mtu(struct net_device *dev, int mtu)
 {
-       int max = xennet_can_sg(dev) ?
-               XEN_NETIF_MAX_TX_SIZE - MAX_TCP_HEADER : ETH_DATA_LEN;
+       int max = xennet_can_sg(dev) ? XEN_NETIF_MAX_TX_SIZE : ETH_DATA_LEN;
 
        if (mtu > max)
                return -EINVAL;
@@ -1279,8 +1278,6 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev)
        netdev->ethtool_ops = &xennet_ethtool_ops;
        SET_NETDEV_DEV(netdev, &dev->dev);
 
-       netif_set_gso_max_size(netdev, XEN_NETIF_MAX_TX_SIZE - MAX_TCP_HEADER);
-
        np->netdev = netdev;
 
        netif_carrier_off(netdev);
index 7563f36c71db344740c3d9821435a1285533b6ed..fcacb186a67beee65742542f86fc45feff8e4352 100644 (file)
@@ -6,8 +6,7 @@ obj-$(CONFIG_OF_PROMTREE) += pdt.o
 obj-$(CONFIG_OF_ADDRESS)  += address.o
 obj-$(CONFIG_OF_IRQ)    += irq.o
 obj-$(CONFIG_OF_NET)   += of_net.o
-obj-$(CONFIG_OF_UNITTEST) += of_unittest.o
-of_unittest-objs := unittest.o unittest-data/testcases.dtb.o
+obj-$(CONFIG_OF_UNITTEST) += unittest.o
 obj-$(CONFIG_OF_MDIO)  += of_mdio.o
 obj-$(CONFIG_OF_PCI)   += of_pci.o
 obj-$(CONFIG_OF_PCI_IRQ)  += of_pci_irq.o
@@ -16,5 +15,7 @@ obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
 obj-$(CONFIG_OF_RESOLVE)  += resolver.o
 obj-$(CONFIG_OF_OVERLAY) += overlay.o
 
+obj-$(CONFIG_OF_UNITTEST) += unittest-data/
+
 CFLAGS_fdt.o = -I$(src)/../../scripts/dtc/libfdt
 CFLAGS_fdt_address.o = -I$(src)/../../scripts/dtc/libfdt
index ad2906919d4589f4edbc0cd599a2fe7aa2938922..78a7dcbec7d8990ac37adad938a0aff3420423e2 100644 (file)
@@ -450,12 +450,17 @@ static struct of_bus *of_match_bus(struct device_node *np)
        return NULL;
 }
 
-static int of_empty_ranges_quirk(void)
+static int of_empty_ranges_quirk(struct device_node *np)
 {
        if (IS_ENABLED(CONFIG_PPC)) {
-               /* To save cycles, we cache the result */
+               /* To save cycles, we cache the result for global "Mac" setting */
                static int quirk_state = -1;
 
+               /* PA-SEMI sdc DT bug */
+               if (of_device_is_compatible(np, "1682m-sdc"))
+                       return true;
+
+               /* Make quirk cached */
                if (quirk_state < 0)
                        quirk_state =
                                of_machine_is_compatible("Power Macintosh") ||
@@ -490,7 +495,7 @@ 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 (ranges == NULL && !of_empty_ranges_quirk()) {
+       if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
                pr_debug("OF: no ranges; cannot translate\n");
                return 1;
        }
index 8f165b112e03a285899655984491b000f0020e17..69566b6a876d76c4db311685ca2020632142673c 100644 (file)
@@ -2082,14 +2082,45 @@ int of_graph_parse_endpoint(const struct device_node *node,
 }
 EXPORT_SYMBOL(of_graph_parse_endpoint);
 
+/**
+ * of_graph_get_port_by_id() - get the port matching a given id
+ * @parent: pointer to the parent device node
+ * @id: id of the port
+ *
+ * Return: A 'port' node pointer with refcount incremented. The caller
+ * has to use of_node_put() on it when done.
+ */
+struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
+{
+       struct device_node *node, *port;
+
+       node = of_get_child_by_name(parent, "ports");
+       if (node)
+               parent = node;
+
+       for_each_child_of_node(parent, port) {
+               u32 port_id = 0;
+
+               if (of_node_cmp(port->name, "port") != 0)
+                       continue;
+               of_property_read_u32(port, "reg", &port_id);
+               if (id == port_id)
+                       break;
+       }
+
+       of_node_put(node);
+
+       return port;
+}
+EXPORT_SYMBOL(of_graph_get_port_by_id);
+
 /**
  * of_graph_get_next_endpoint() - get next endpoint node
  * @parent: pointer to the parent device node
  * @prev: previous endpoint node, or NULL to get first
  *
  * Return: An 'endpoint' node pointer with refcount incremented. Refcount
- * of the passed @prev node is not decremented, the caller have to use
- * of_node_put() on it when done.
+ * of the passed @prev node is decremented.
  */
 struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
                                        struct device_node *prev)
@@ -2125,12 +2156,6 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
                if (WARN_ONCE(!port, "%s(): endpoint %s has no parent node\n",
                              __func__, prev->full_name))
                        return NULL;
-
-               /*
-                * Avoid dropping prev node refcount to 0 when getting the next
-                * child below.
-                */
-               of_node_get(prev);
        }
 
        while (1) {
diff --git a/drivers/of/unittest-data/.gitignore b/drivers/of/unittest-data/.gitignore
new file mode 100644 (file)
index 0000000..4b3cf8b
--- /dev/null
@@ -0,0 +1,2 @@
+testcases.dtb
+testcases.dtb.S
diff --git a/drivers/of/unittest-data/Makefile b/drivers/of/unittest-data/Makefile
new file mode 100644 (file)
index 0000000..1ac5cc0
--- /dev/null
@@ -0,0 +1,7 @@
+obj-y += testcases.dtb.o
+
+targets += testcases.dtb testcases.dtb.S
+
+.SECONDARY: \
+       $(obj)/testcases.dtb.S \
+       $(obj)/testcases.dtb
index 244226cbb5a3b7fb8929fd75b77171cb172c1aa9..02ba56c20fe1247b7ec435eb34d7a6a2b84eca38 100644 (file)
@@ -4,94 +4,94 @@
                overlay-node {
 
                        /* test bus */
-                       selftestbus: test-bus {
+                       unittestbus: test-bus {
                                compatible = "simple-bus";
                                #address-cells = <1>;
                                #size-cells = <0>;
 
-                               selftest100: test-selftest100 {
-                                       compatible = "selftest";
+                               unittest100: test-unittest100 {
+                                       compatible = "unittest";
                                        status = "okay";
                                        reg = <100>;
                                };
 
-                               selftest101: test-selftest101 {
-                                       compatible = "selftest";
+                               unittest101: test-unittest101 {
+                                       compatible = "unittest";
                                        status = "disabled";
                                        reg = <101>;
                                };
 
-                               selftest0: test-selftest0 {
-                                       compatible = "selftest";
+                               unittest0: test-unittest0 {
+                                       compatible = "unittest";
                                        status = "disabled";
                                        reg = <0>;
                                };
 
-                               selftest1: test-selftest1 {
-                                       compatible = "selftest";
+                               unittest1: test-unittest1 {
+                                       compatible = "unittest";
                                        status = "okay";
                                        reg = <1>;
                                };
 
-                               selftest2: test-selftest2 {
-                                       compatible = "selftest";
+                               unittest2: test-unittest2 {
+                                       compatible = "unittest";
                                        status = "disabled";
                                        reg = <2>;
                                };
 
-                               selftest3: test-selftest3 {
-                                       compatible = "selftest";
+                               unittest3: test-unittest3 {
+                                       compatible = "unittest";
                                        status = "okay";
                                        reg = <3>;
                                };
 
-                               selftest5: test-selftest5 {
-                                       compatible = "selftest";
+                               unittest5: test-unittest5 {
+                                       compatible = "unittest";
                                        status = "disabled";
                                        reg = <5>;
                                };
 
-                               selftest6: test-selftest6 {
-                                       compatible = "selftest";
+                               unittest6: test-unittest6 {
+                                       compatible = "unittest";
                                        status = "disabled";
                                        reg = <6>;
                                };
 
-                               selftest7: test-selftest7 {
-                                       compatible = "selftest";
+                               unittest7: test-unittest7 {
+                                       compatible = "unittest";
                                        status = "disabled";
                                        reg = <7>;
                                };
 
-                               selftest8: test-selftest8 {
-                                       compatible = "selftest";
+                               unittest8: test-unittest8 {
+                                       compatible = "unittest";
                                        status = "disabled";
                                        reg = <8>;
                                };
 
                                i2c-test-bus {
-                                       compatible = "selftest-i2c-bus";
+                                       compatible = "unittest-i2c-bus";
                                        status = "okay";
                                        reg = <50>;
 
                                        #address-cells = <1>;
                                        #size-cells = <0>;
 
-                                       test-selftest12 {
+                                       test-unittest12 {
                                                reg = <8>;
-                                               compatible = "selftest-i2c-dev";
+                                               compatible = "unittest-i2c-dev";
                                                status = "disabled";
                                        };
 
-                                       test-selftest13 {
+                                       test-unittest13 {
                                                reg = <9>;
-                                               compatible = "selftest-i2c-dev";
+                                               compatible = "unittest-i2c-dev";
                                                status = "okay";
                                        };
 
-                                       test-selftest14 {
+                                       test-unittest14 {
                                                reg = <10>;
-                                               compatible = "selftest-i2c-mux";
+                                               compatible = "unittest-i2c-mux";
                                                status = "okay";
 
                                                #address-cells = <1>;
 
                                                        test-mux-dev {
                                                                reg = <32>;
-                                                               compatible = "selftest-i2c-dev";
+                                                               compatible = "unittest-i2c-dev";
                                                                status = "okay";
                                                        };
                                                };
                /* test enable using absolute target path */
                overlay0 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/test-selftest0";
+                               target-path = "/testcase-data/overlay-node/test-bus/test-unittest0";
                                __overlay__ {
                                        status = "okay";
                                };
                /* test disable using absolute target path */
                overlay1 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/test-selftest1";
+                               target-path = "/testcase-data/overlay-node/test-bus/test-unittest1";
                                __overlay__ {
                                        status = "disabled";
                                };
                /* test enable using label */
                overlay2 {
                        fragment@0 {
-                               target = <&selftest2>;
+                               target = <&unittest2>;
                                __overlay__ {
                                        status = "okay";
                                };
                /* test disable using label */
                overlay3 {
                        fragment@0 {
-                               target = <&selftest3>;
+                               target = <&unittest3>;
                                __overlay__ {
                                        status = "disabled";
                                };
                /* test insertion of a full node */
                overlay4 {
                        fragment@0 {
-                               target = <&selftestbus>;
+                               target = <&unittestbus>;
                                __overlay__ {
 
                                        /* suppress DTC warning */
                                        #address-cells = <1>;
                                        #size-cells = <0>;
 
-                                       test-selftest4 {
-                                               compatible = "selftest";
+                                       test-unittest4 {
+                                               compatible = "unittest";
                                                status = "okay";
                                                reg = <4>;
                                        };
                /* test overlay apply revert */
                overlay5 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/test-selftest5";
+                               target-path = "/testcase-data/overlay-node/test-bus/test-unittest5";
                                __overlay__ {
                                        status = "okay";
                                };
                /* test overlays application and removal in sequence */
                overlay6 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/test-selftest6";
+                               target-path = "/testcase-data/overlay-node/test-bus/test-unittest6";
                                __overlay__ {
                                        status = "okay";
                                };
                };
                overlay7 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/test-selftest7";
+                               target-path = "/testcase-data/overlay-node/test-bus/test-unittest7";
                                __overlay__ {
                                        status = "okay";
                                };
                /* test overlays application and removal in bad sequence */
                overlay8 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/test-selftest8";
+                               target-path = "/testcase-data/overlay-node/test-bus/test-unittest8";
                                __overlay__ {
                                        status = "okay";
                                };
                };
                overlay9 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/test-selftest8";
+                               target-path = "/testcase-data/overlay-node/test-bus/test-unittest8";
                                __overlay__ {
                                        property-foo = "bar";
                                };
                                        #address-cells = <1>;
                                        #size-cells = <0>;
 
-                                       test-selftest10 {
-                                               compatible = "selftest";
+                                       test-unittest10 {
+                                               compatible = "unittest";
                                                status = "okay";
                                                reg = <10>;
 
                                                #address-cells = <1>;
                                                #size-cells = <0>;
 
-                                               test-selftest101 {
-                                                       compatible = "selftest";
+                                               test-unittest101 {
+                                                       compatible = "unittest";
                                                        status = "okay";
                                                        reg = <1>;
                                                };
                                        #address-cells = <1>;
                                        #size-cells = <0>;
 
-                                       test-selftest11 {
-                                               compatible = "selftest";
+                                       test-unittest11 {
+                                               compatible = "unittest";
                                                status = "okay";
                                                reg = <11>;
 
                                                #address-cells = <1>;
                                                #size-cells = <0>;
 
-                                               test-selftest111 {
-                                                       compatible = "selftest";
+                                               test-unittest111 {
+                                                       compatible = "unittest";
                                                        status = "okay";
                                                        reg = <1>;
                                                };
                /* test enable using absolute target path (i2c) */
                overlay12 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-selftest12";
+                               target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest12";
                                __overlay__ {
                                        status = "okay";
                                };
                /* test disable using absolute target path (i2c) */
                overlay13 {
                        fragment@0 {
-                               target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-selftest13";
+                               target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest13";
                                __overlay__ {
                                        status = "disabled";
                                };
                                __overlay__ {
                                        #address-cells = <1>;
                                        #size-cells = <0>;
-                                       test-selftest15 {
+                                       test-unittest15 {
                                                reg = <11>;
-                                               compatible = "selftest-i2c-mux";
+                                               compatible = "unittest-i2c-mux";
                                                status = "okay";
 
                                                #address-cells = <1>;
 
                                                        test-mux-dev {
                                                                reg = <32>;
-                                                               compatible = "selftest-i2c-dev";
+                                                               compatible = "unittest-i2c-dev";
                                                                status = "okay";
                                                        };
                                                };
index 52c45c7df07ff6623c7fb7656961f8bdcf804da3..fdb597766be98de959287769b411ee6038d172ee 100644 (file)
 
 #include "of_private.h"
 
-static struct selftest_results {
+static struct unittest_results {
        int passed;
        int failed;
-} selftest_results;
+} unittest_results;
 
-#define selftest(result, fmt, ...) ({ \
+#define unittest(result, fmt, ...) ({ \
        bool failed = !(result); \
        if (failed) { \
-               selftest_results.failed++; \
+               unittest_results.failed++; \
                pr_err("FAIL %s():%i " fmt, __func__, __LINE__, ##__VA_ARGS__); \
        } else { \
-               selftest_results.passed++; \
+               unittest_results.passed++; \
                pr_debug("pass %s():%i\n", __func__, __LINE__); \
        } \
        failed; \
 })
 
-static void __init of_selftest_find_node_by_name(void)
+static void __init of_unittest_find_node_by_name(void)
 {
        struct device_node *np;
        const char *options;
 
        np = of_find_node_by_path("/testcase-data");
-       selftest(np && !strcmp("/testcase-data", np->full_name),
+       unittest(np && !strcmp("/testcase-data", np->full_name),
                "find /testcase-data failed\n");
        of_node_put(np);
 
        /* Test if trailing '/' works */
        np = of_find_node_by_path("/testcase-data/");
-       selftest(!np, "trailing '/' on /testcase-data/ should fail\n");
+       unittest(!np, "trailing '/' on /testcase-data/ should fail\n");
 
        np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
-       selftest(np && !strcmp("/testcase-data/phandle-tests/consumer-a", np->full_name),
+       unittest(np && !strcmp("/testcase-data/phandle-tests/consumer-a", np->full_name),
                "find /testcase-data/phandle-tests/consumer-a failed\n");
        of_node_put(np);
 
        np = of_find_node_by_path("testcase-alias");
-       selftest(np && !strcmp("/testcase-data", np->full_name),
+       unittest(np && !strcmp("/testcase-data", np->full_name),
                "find testcase-alias failed\n");
        of_node_put(np);
 
        /* Test if trailing '/' works on aliases */
        np = of_find_node_by_path("testcase-alias/");
-       selftest(!np, "trailing '/' on testcase-alias/ should fail\n");
+       unittest(!np, "trailing '/' on testcase-alias/ should fail\n");
 
        np = of_find_node_by_path("testcase-alias/phandle-tests/consumer-a");
-       selftest(np && !strcmp("/testcase-data/phandle-tests/consumer-a", np->full_name),
+       unittest(np && !strcmp("/testcase-data/phandle-tests/consumer-a", np->full_name),
                "find testcase-alias/phandle-tests/consumer-a failed\n");
        of_node_put(np);
 
        np = of_find_node_by_path("/testcase-data/missing-path");
-       selftest(!np, "non-existent path returned node %s\n", np->full_name);
+       unittest(!np, "non-existent path returned node %s\n", np->full_name);
        of_node_put(np);
 
        np = of_find_node_by_path("missing-alias");
-       selftest(!np, "non-existent alias returned node %s\n", np->full_name);
+       unittest(!np, "non-existent alias returned node %s\n", np->full_name);
        of_node_put(np);
 
        np = of_find_node_by_path("testcase-alias/missing-path");
-       selftest(!np, "non-existent alias with relative path returned node %s\n", np->full_name);
+       unittest(!np, "non-existent alias with relative path returned node %s\n", np->full_name);
        of_node_put(np);
 
        np = of_find_node_opts_by_path("/testcase-data:testoption", &options);
-       selftest(np && !strcmp("testoption", options),
+       unittest(np && !strcmp("testoption", options),
                 "option path test failed\n");
        of_node_put(np);
 
        np = of_find_node_opts_by_path("/testcase-data:test/option", &options);
-       selftest(np && !strcmp("test/option", options),
+       unittest(np && !strcmp("test/option", options),
                 "option path test, subcase #1 failed\n");
        of_node_put(np);
 
        np = of_find_node_opts_by_path("/testcase-data/testcase-device1:test/option", &options);
-       selftest(np && !strcmp("test/option", options),
+       unittest(np && !strcmp("test/option", options),
                 "option path test, subcase #2 failed\n");
        of_node_put(np);
 
        np = of_find_node_opts_by_path("/testcase-data:testoption", NULL);
-       selftest(np, "NULL option path test failed\n");
+       unittest(np, "NULL option path test failed\n");
        of_node_put(np);
 
        np = of_find_node_opts_by_path("testcase-alias:testaliasoption",
                                       &options);
-       selftest(np && !strcmp("testaliasoption", options),
+       unittest(np && !strcmp("testaliasoption", options),
                 "option alias path test failed\n");
        of_node_put(np);
 
        np = of_find_node_opts_by_path("testcase-alias:test/alias/option",
                                       &options);
-       selftest(np && !strcmp("test/alias/option", options),
+       unittest(np && !strcmp("test/alias/option", options),
                 "option alias path test, subcase #1 failed\n");
        of_node_put(np);
 
        np = of_find_node_opts_by_path("testcase-alias:testaliasoption", NULL);
-       selftest(np, "NULL option alias path test failed\n");
+       unittest(np, "NULL option alias path test failed\n");
        of_node_put(np);
 
        options = "testoption";
        np = of_find_node_opts_by_path("testcase-alias", &options);
-       selftest(np && !options, "option clearing test failed\n");
+       unittest(np && !options, "option clearing test failed\n");
        of_node_put(np);
 
        options = "testoption";
        np = of_find_node_opts_by_path("/", &options);
-       selftest(np && !options, "option clearing root node test failed\n");
+       unittest(np && !options, "option clearing root node test failed\n");
        of_node_put(np);
 }
 
-static void __init of_selftest_dynamic(void)
+static void __init of_unittest_dynamic(void)
 {
        struct device_node *np;
        struct property *prop;
@@ -147,7 +147,7 @@ static void __init of_selftest_dynamic(void)
        /* Array of 4 properties for the purpose of testing */
        prop = kzalloc(sizeof(*prop) * 4, GFP_KERNEL);
        if (!prop) {
-               selftest(0, "kzalloc() failed\n");
+               unittest(0, "kzalloc() failed\n");
                return;
        }
 
@@ -155,20 +155,20 @@ static void __init of_selftest_dynamic(void)
        prop->name = "new-property";
        prop->value = "new-property-data";
        prop->length = strlen(prop->value);
-       selftest(of_add_property(np, prop) == 0, "Adding a new property failed\n");
+       unittest(of_add_property(np, prop) == 0, "Adding a new property failed\n");
 
        /* Try to add an existing property - should fail */
        prop++;
        prop->name = "new-property";
        prop->value = "new-property-data-should-fail";
        prop->length = strlen(prop->value);
-       selftest(of_add_property(np, prop) != 0,
+       unittest(of_add_property(np, prop) != 0,
                 "Adding an existing property should have failed\n");
 
        /* Try to modify an existing property - should pass */
        prop->value = "modify-property-data-should-pass";
        prop->length = strlen(prop->value);
-       selftest(of_update_property(np, prop) == 0,
+       unittest(of_update_property(np, prop) == 0,
                 "Updating an existing property should have passed\n");
 
        /* Try to modify non-existent property - should pass*/
@@ -176,11 +176,11 @@ static void __init of_selftest_dynamic(void)
        prop->name = "modify-property";
        prop->value = "modify-missing-property-data-should-pass";
        prop->length = strlen(prop->value);
-       selftest(of_update_property(np, prop) == 0,
+       unittest(of_update_property(np, prop) == 0,
                 "Updating a missing property should have passed\n");
 
        /* Remove property - should pass */
-       selftest(of_remove_property(np, prop) == 0,
+       unittest(of_remove_property(np, prop) == 0,
                 "Removing a property should have passed\n");
 
        /* Adding very large property - should pass */
@@ -188,13 +188,13 @@ static void __init of_selftest_dynamic(void)
        prop->name = "large-property-PAGE_SIZEx8";
        prop->length = PAGE_SIZE * 8;
        prop->value = kzalloc(prop->length, GFP_KERNEL);
-       selftest(prop->value != NULL, "Unable to allocate large buffer\n");
+       unittest(prop->value != NULL, "Unable to allocate large buffer\n");
        if (prop->value)
-               selftest(of_add_property(np, prop) == 0,
+               unittest(of_add_property(np, prop) == 0,
                         "Adding a large property should have passed\n");
 }
 
-static int __init of_selftest_check_node_linkage(struct device_node *np)
+static int __init of_unittest_check_node_linkage(struct device_node *np)
 {
        struct device_node *child;
        int count = 0, rc;
@@ -206,7 +206,7 @@ static int __init of_selftest_check_node_linkage(struct device_node *np)
                        return -EINVAL;
                }
 
-               rc = of_selftest_check_node_linkage(child);
+               rc = of_unittest_check_node_linkage(child);
                if (rc < 0)
                        return rc;
                count += rc;
@@ -215,7 +215,7 @@ static int __init of_selftest_check_node_linkage(struct device_node *np)
        return count + 1;
 }
 
-static void __init of_selftest_check_tree_linkage(void)
+static void __init of_unittest_check_tree_linkage(void)
 {
        struct device_node *np;
        int allnode_count = 0, child_count;
@@ -225,10 +225,10 @@ static void __init of_selftest_check_tree_linkage(void)
 
        for_each_of_allnodes(np)
                allnode_count++;
-       child_count = of_selftest_check_node_linkage(of_root);
+       child_count = of_unittest_check_node_linkage(of_root);
 
-       selftest(child_count > 0, "Device node data structure is corrupted\n");
-       selftest(child_count == allnode_count, "allnodes list size (%i) doesn't match"
+       unittest(child_count > 0, "Device node data structure is corrupted\n");
+       unittest(child_count == allnode_count, "allnodes list size (%i) doesn't match"
                 "sibling lists size (%i)\n", allnode_count, child_count);
        pr_debug("allnodes list size (%i); sibling lists size (%i)\n", allnode_count, child_count);
 }
@@ -239,7 +239,7 @@ struct node_hash {
 };
 
 static DEFINE_HASHTABLE(phandle_ht, 8);
-static void __init of_selftest_check_phandles(void)
+static void __init of_unittest_check_phandles(void)
 {
        struct device_node *np;
        struct node_hash *nh;
@@ -267,7 +267,7 @@ static void __init of_selftest_check_phandles(void)
                hash_add(phandle_ht, &nh->node, np->phandle);
                phandle_count++;
        }
-       selftest(dup_count == 0, "Found %i duplicates in %i phandles\n",
+       unittest(dup_count == 0, "Found %i duplicates in %i phandles\n",
                 dup_count, phandle_count);
 
        /* Clean up */
@@ -277,7 +277,7 @@ static void __init of_selftest_check_phandles(void)
        }
 }
 
-static void __init of_selftest_parse_phandle_with_args(void)
+static void __init of_unittest_parse_phandle_with_args(void)
 {
        struct device_node *np;
        struct of_phandle_args args;
@@ -290,7 +290,7 @@ static void __init of_selftest_parse_phandle_with_args(void)
        }
 
        rc = of_count_phandle_with_args(np, "phandle-list", "#phandle-cells");
-       selftest(rc == 7, "of_count_phandle_with_args() returned %i, expected 7\n", rc);
+       unittest(rc == 7, "of_count_phandle_with_args() returned %i, expected 7\n", rc);
 
        for (i = 0; i < 8; i++) {
                bool passed = true;
@@ -342,44 +342,44 @@ static void __init of_selftest_parse_phandle_with_args(void)
                        passed = false;
                }
 
-               selftest(passed, "index %i - data error on node %s rc=%i\n",
+               unittest(passed, "index %i - data error on node %s rc=%i\n",
                         i, args.np->full_name, rc);
        }
 
        /* Check for missing list property */
        rc = of_parse_phandle_with_args(np, "phandle-list-missing",
                                        "#phandle-cells", 0, &args);
-       selftest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
+       unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
        rc = of_count_phandle_with_args(np, "phandle-list-missing",
                                        "#phandle-cells");
-       selftest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
+       unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
 
        /* Check for missing cells property */
        rc = of_parse_phandle_with_args(np, "phandle-list",
                                        "#phandle-cells-missing", 0, &args);
-       selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+       unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
        rc = of_count_phandle_with_args(np, "phandle-list",
                                        "#phandle-cells-missing");
-       selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+       unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
 
        /* Check for bad phandle in list */
        rc = of_parse_phandle_with_args(np, "phandle-list-bad-phandle",
                                        "#phandle-cells", 0, &args);
-       selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+       unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
        rc = of_count_phandle_with_args(np, "phandle-list-bad-phandle",
                                        "#phandle-cells");
-       selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+       unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
 
        /* Check for incorrectly formed argument list */
        rc = of_parse_phandle_with_args(np, "phandle-list-bad-args",
                                        "#phandle-cells", 1, &args);
-       selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+       unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
        rc = of_count_phandle_with_args(np, "phandle-list-bad-args",
                                        "#phandle-cells");
-       selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+       unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
 }
 
-static void __init of_selftest_property_string(void)
+static void __init of_unittest_property_string(void)
 {
        const char *strings[4];
        struct device_node *np;
@@ -392,79 +392,79 @@ static void __init of_selftest_property_string(void)
        }
 
        rc = of_property_match_string(np, "phandle-list-names", "first");
-       selftest(rc == 0, "first expected:0 got:%i\n", rc);
+       unittest(rc == 0, "first expected:0 got:%i\n", rc);
        rc = of_property_match_string(np, "phandle-list-names", "second");
-       selftest(rc == 1, "second expected:1 got:%i\n", rc);
+       unittest(rc == 1, "second expected:1 got:%i\n", rc);
        rc = of_property_match_string(np, "phandle-list-names", "third");
-       selftest(rc == 2, "third expected:2 got:%i\n", rc);
+       unittest(rc == 2, "third expected:2 got:%i\n", rc);
        rc = of_property_match_string(np, "phandle-list-names", "fourth");
-       selftest(rc == -ENODATA, "unmatched string; rc=%i\n", rc);
+       unittest(rc == -ENODATA, "unmatched string; rc=%i\n", rc);
        rc = of_property_match_string(np, "missing-property", "blah");
-       selftest(rc == -EINVAL, "missing property; rc=%i\n", rc);
+       unittest(rc == -EINVAL, "missing property; rc=%i\n", rc);
        rc = of_property_match_string(np, "empty-property", "blah");
-       selftest(rc == -ENODATA, "empty property; rc=%i\n", rc);
+       unittest(rc == -ENODATA, "empty property; rc=%i\n", rc);
        rc = of_property_match_string(np, "unterminated-string", "blah");
-       selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
+       unittest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
 
        /* of_property_count_strings() tests */
        rc = of_property_count_strings(np, "string-property");
-       selftest(rc == 1, "Incorrect string count; rc=%i\n", rc);
+       unittest(rc == 1, "Incorrect string count; rc=%i\n", rc);
        rc = of_property_count_strings(np, "phandle-list-names");
-       selftest(rc == 3, "Incorrect string count; rc=%i\n", rc);
+       unittest(rc == 3, "Incorrect string count; rc=%i\n", rc);
        rc = of_property_count_strings(np, "unterminated-string");
-       selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
+       unittest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
        rc = of_property_count_strings(np, "unterminated-string-list");
-       selftest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc);
+       unittest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc);
 
        /* of_property_read_string_index() tests */
        rc = of_property_read_string_index(np, "string-property", 0, strings);
-       selftest(rc == 0 && !strcmp(strings[0], "foobar"), "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == 0 && !strcmp(strings[0], "foobar"), "of_property_read_string_index() failure; rc=%i\n", rc);
        strings[0] = NULL;
        rc = of_property_read_string_index(np, "string-property", 1, strings);
-       selftest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
        rc = of_property_read_string_index(np, "phandle-list-names", 0, strings);
-       selftest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc);
        rc = of_property_read_string_index(np, "phandle-list-names", 1, strings);
-       selftest(rc == 0 && !strcmp(strings[0], "second"), "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == 0 && !strcmp(strings[0], "second"), "of_property_read_string_index() failure; rc=%i\n", rc);
        rc = of_property_read_string_index(np, "phandle-list-names", 2, strings);
-       selftest(rc == 0 && !strcmp(strings[0], "third"), "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == 0 && !strcmp(strings[0], "third"), "of_property_read_string_index() failure; rc=%i\n", rc);
        strings[0] = NULL;
        rc = of_property_read_string_index(np, "phandle-list-names", 3, strings);
-       selftest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
        strings[0] = NULL;
        rc = of_property_read_string_index(np, "unterminated-string", 0, strings);
-       selftest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
        rc = of_property_read_string_index(np, "unterminated-string-list", 0, strings);
-       selftest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc);
        strings[0] = NULL;
        rc = of_property_read_string_index(np, "unterminated-string-list", 2, strings); /* should fail */
-       selftest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
+       unittest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
        strings[1] = NULL;
 
        /* of_property_read_string_array() tests */
        rc = of_property_read_string_array(np, "string-property", strings, 4);
-       selftest(rc == 1, "Incorrect string count; rc=%i\n", rc);
+       unittest(rc == 1, "Incorrect string count; rc=%i\n", rc);
        rc = of_property_read_string_array(np, "phandle-list-names", strings, 4);
-       selftest(rc == 3, "Incorrect string count; rc=%i\n", rc);
+       unittest(rc == 3, "Incorrect string count; rc=%i\n", rc);
        rc = of_property_read_string_array(np, "unterminated-string", strings, 4);
-       selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
+       unittest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
        /* -- An incorrectly formed string should cause a failure */
        rc = of_property_read_string_array(np, "unterminated-string-list", strings, 4);
-       selftest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc);
+       unittest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc);
        /* -- parsing the correctly formed strings should still work: */
        strings[2] = NULL;
        rc = of_property_read_string_array(np, "unterminated-string-list", strings, 2);
-       selftest(rc == 2 && strings[2] == NULL, "of_property_read_string_array() failure; rc=%i\n", rc);
+       unittest(rc == 2 && strings[2] == NULL, "of_property_read_string_array() failure; rc=%i\n", rc);
        strings[1] = NULL;
        rc = of_property_read_string_array(np, "phandle-list-names", strings, 1);
-       selftest(rc == 1 && strings[1] == NULL, "Overwrote end of string array; rc=%i, str='%s'\n", rc, strings[1]);
+       unittest(rc == 1 && strings[1] == NULL, "Overwrote end of string array; rc=%i, str='%s'\n", rc, strings[1]);
 }
 
 #define propcmp(p1, p2) (((p1)->length == (p2)->length) && \
                        (p1)->value && (p2)->value && \
                        !memcmp((p1)->value, (p2)->value, (p1)->length) && \
                        !strcmp((p1)->name, (p2)->name))
-static void __init of_selftest_property_copy(void)
+static void __init of_unittest_property_copy(void)
 {
 #ifdef CONFIG_OF_DYNAMIC
        struct property p1 = { .name = "p1", .length = 0, .value = "" };
@@ -472,20 +472,20 @@ static void __init of_selftest_property_copy(void)
        struct property *new;
 
        new = __of_prop_dup(&p1, GFP_KERNEL);
-       selftest(new && propcmp(&p1, new), "empty property didn't copy correctly\n");
+       unittest(new && propcmp(&p1, new), "empty property didn't copy correctly\n");
        kfree(new->value);
        kfree(new->name);
        kfree(new);
 
        new = __of_prop_dup(&p2, GFP_KERNEL);
-       selftest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n");
+       unittest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n");
        kfree(new->value);
        kfree(new->name);
        kfree(new);
 #endif
 }
 
-static void __init of_selftest_changeset(void)
+static void __init of_unittest_changeset(void)
 {
 #ifdef CONFIG_OF_DYNAMIC
        struct property *ppadd, padd = { .name = "prop-add", .length = 0, .value = "" };
@@ -495,51 +495,51 @@ static void __init of_selftest_changeset(void)
        struct of_changeset chgset;
 
        n1 = __of_node_dup(NULL, "/testcase-data/changeset/n1");
-       selftest(n1, "testcase setup failure\n");
+       unittest(n1, "testcase setup failure\n");
        n2 = __of_node_dup(NULL, "/testcase-data/changeset/n2");
-       selftest(n2, "testcase setup failure\n");
+       unittest(n2, "testcase setup failure\n");
        n21 = __of_node_dup(NULL, "%s/%s", "/testcase-data/changeset/n2", "n21");
-       selftest(n21, "testcase setup failure %p\n", n21);
+       unittest(n21, "testcase setup failure %p\n", n21);
        nremove = of_find_node_by_path("/testcase-data/changeset/node-remove");
-       selftest(nremove, "testcase setup failure\n");
+       unittest(nremove, "testcase setup failure\n");
        ppadd = __of_prop_dup(&padd, GFP_KERNEL);
-       selftest(ppadd, "testcase setup failure\n");
+       unittest(ppadd, "testcase setup failure\n");
        ppupdate = __of_prop_dup(&pupdate, GFP_KERNEL);
-       selftest(ppupdate, "testcase setup failure\n");
+       unittest(ppupdate, "testcase setup failure\n");
        parent = nremove->parent;
        n1->parent = parent;
        n2->parent = parent;
        n21->parent = n2;
        n2->child = n21;
        ppremove = of_find_property(parent, "prop-remove", NULL);
-       selftest(ppremove, "failed to find removal prop");
+       unittest(ppremove, "failed to find removal prop");
 
        of_changeset_init(&chgset);
-       selftest(!of_changeset_attach_node(&chgset, n1), "fail attach n1\n");
-       selftest(!of_changeset_attach_node(&chgset, n2), "fail attach n2\n");
-       selftest(!of_changeset_detach_node(&chgset, nremove), "fail remove node\n");
-       selftest(!of_changeset_attach_node(&chgset, n21), "fail attach n21\n");
-       selftest(!of_changeset_add_property(&chgset, parent, ppadd), "fail add prop\n");
-       selftest(!of_changeset_update_property(&chgset, parent, ppupdate), "fail update prop\n");
-       selftest(!of_changeset_remove_property(&chgset, parent, ppremove), "fail remove prop\n");
+       unittest(!of_changeset_attach_node(&chgset, n1), "fail attach n1\n");
+       unittest(!of_changeset_attach_node(&chgset, n2), "fail attach n2\n");
+       unittest(!of_changeset_detach_node(&chgset, nremove), "fail remove node\n");
+       unittest(!of_changeset_attach_node(&chgset, n21), "fail attach n21\n");
+       unittest(!of_changeset_add_property(&chgset, parent, ppadd), "fail add prop\n");
+       unittest(!of_changeset_update_property(&chgset, parent, ppupdate), "fail update prop\n");
+       unittest(!of_changeset_remove_property(&chgset, parent, ppremove), "fail remove prop\n");
        mutex_lock(&of_mutex);
-       selftest(!of_changeset_apply(&chgset), "apply failed\n");
+       unittest(!of_changeset_apply(&chgset), "apply failed\n");
        mutex_unlock(&of_mutex);
 
        /* Make sure node names are constructed correctly */
-       selftest((np = of_find_node_by_path("/testcase-data/changeset/n2/n21")),
+       unittest((np = of_find_node_by_path("/testcase-data/changeset/n2/n21")),
                 "'%s' not added\n", n21->full_name);
        of_node_put(np);
 
        mutex_lock(&of_mutex);
-       selftest(!of_changeset_revert(&chgset), "revert failed\n");
+       unittest(!of_changeset_revert(&chgset), "revert failed\n");
        mutex_unlock(&of_mutex);
 
        of_changeset_destroy(&chgset);
 #endif
 }
 
-static void __init of_selftest_parse_interrupts(void)
+static void __init of_unittest_parse_interrupts(void)
 {
        struct device_node *np;
        struct of_phandle_args args;
@@ -560,7 +560,7 @@ static void __init of_selftest_parse_interrupts(void)
                passed &= (args.args_count == 1);
                passed &= (args.args[0] == (i + 1));
 
-               selftest(passed, "index %i - data error on node %s rc=%i\n",
+               unittest(passed, "index %i - data error on node %s rc=%i\n",
                         i, args.np->full_name, rc);
        }
        of_node_put(np);
@@ -605,13 +605,13 @@ static void __init of_selftest_parse_interrupts(void)
                default:
                        passed = false;
                }
-               selftest(passed, "index %i - data error on node %s rc=%i\n",
+               unittest(passed, "index %i - data error on node %s rc=%i\n",
                         i, args.np->full_name, rc);
        }
        of_node_put(np);
 }
 
-static void __init of_selftest_parse_interrupts_extended(void)
+static void __init of_unittest_parse_interrupts_extended(void)
 {
        struct device_node *np;
        struct of_phandle_args args;
@@ -674,7 +674,7 @@ static void __init of_selftest_parse_interrupts_extended(void)
                        passed = false;
                }
 
-               selftest(passed, "index %i - data error on node %s rc=%i\n",
+               unittest(passed, "index %i - data error on node %s rc=%i\n",
                         i, args.np->full_name, rc);
        }
        of_node_put(np);
@@ -715,7 +715,7 @@ static struct {
        { .path = "/testcase-data/match-node/name9", .data = "K", },
 };
 
-static void __init of_selftest_match_node(void)
+static void __init of_unittest_match_node(void)
 {
        struct device_node *np;
        const struct of_device_id *match;
@@ -724,32 +724,32 @@ static void __init of_selftest_match_node(void)
        for (i = 0; i < ARRAY_SIZE(match_node_tests); i++) {
                np = of_find_node_by_path(match_node_tests[i].path);
                if (!np) {
-                       selftest(0, "missing testcase node %s\n",
+                       unittest(0, "missing testcase node %s\n",
                                match_node_tests[i].path);
                        continue;
                }
 
                match = of_match_node(match_node_table, np);
                if (!match) {
-                       selftest(0, "%s didn't match anything\n",
+                       unittest(0, "%s didn't match anything\n",
                                match_node_tests[i].path);
                        continue;
                }
 
                if (strcmp(match->data, match_node_tests[i].data) != 0) {
-                       selftest(0, "%s got wrong match. expected %s, got %s\n",
+                       unittest(0, "%s got wrong match. expected %s, got %s\n",
                                match_node_tests[i].path, match_node_tests[i].data,
                                (const char *)match->data);
                        continue;
                }
-               selftest(1, "passed");
+               unittest(1, "passed");
        }
 }
 
 struct device test_bus = {
        .init_name = "unittest-bus",
 };
-static void __init of_selftest_platform_populate(void)
+static void __init of_unittest_platform_populate(void)
 {
        int irq, rc;
        struct device_node *np, *child, *grandchild;
@@ -765,30 +765,30 @@ static void __init of_selftest_platform_populate(void)
        /* Test that a missing irq domain returns -EPROBE_DEFER */
        np = of_find_node_by_path("/testcase-data/testcase-device1");
        pdev = of_find_device_by_node(np);
-       selftest(pdev, "device 1 creation failed\n");
+       unittest(pdev, "device 1 creation failed\n");
 
        irq = platform_get_irq(pdev, 0);
-       selftest(irq == -EPROBE_DEFER, "device deferred probe failed - %d\n", irq);
+       unittest(irq == -EPROBE_DEFER, "device deferred probe failed - %d\n", irq);
 
        /* Test that a parsing failure does not return -EPROBE_DEFER */
        np = of_find_node_by_path("/testcase-data/testcase-device2");
        pdev = of_find_device_by_node(np);
-       selftest(pdev, "device 2 creation failed\n");
+       unittest(pdev, "device 2 creation failed\n");
        irq = platform_get_irq(pdev, 0);
-       selftest(irq < 0 && irq != -EPROBE_DEFER, "device parsing error failed - %d\n", irq);
+       unittest(irq < 0 && irq != -EPROBE_DEFER, "device parsing error failed - %d\n", irq);
 
-       if (selftest(np = of_find_node_by_path("/testcase-data/platform-tests"),
+       if (unittest(np = of_find_node_by_path("/testcase-data/platform-tests"),
                     "No testcase data in device tree\n"));
                return;
 
-       if (selftest(!(rc = device_register(&test_bus)),
+       if (unittest(!(rc = device_register(&test_bus)),
                     "testbus registration failed; rc=%i\n", rc));
                return;
 
        for_each_child_of_node(np, child) {
                of_platform_populate(child, match, NULL, &test_bus);
                for_each_child_of_node(child, grandchild)
-                       selftest(of_find_device_by_node(grandchild),
+                       unittest(of_find_device_by_node(grandchild),
                                 "Could not create device for node '%s'\n",
                                 grandchild->name);
        }
@@ -796,7 +796,7 @@ static void __init of_selftest_platform_populate(void)
        of_platform_depopulate(&test_bus);
        for_each_child_of_node(np, child) {
                for_each_child_of_node(child, grandchild)
-                       selftest(!of_find_device_by_node(grandchild),
+                       unittest(!of_find_device_by_node(grandchild),
                                 "device didn't get destroyed '%s'\n",
                                 grandchild->name);
        }
@@ -866,13 +866,13 @@ static int attach_node_and_children(struct device_node *np)
 }
 
 /**
- *     selftest_data_add - Reads, copies data from
+ *     unittest_data_add - Reads, copies data from
  *     linked tree and attaches it to the live tree
  */
-static int __init selftest_data_add(void)
+static int __init unittest_data_add(void)
 {
-       void *selftest_data;
-       struct device_node *selftest_data_node, *np;
+       void *unittest_data;
+       struct device_node *unittest_data_node, *np;
        extern uint8_t __dtb_testcases_begin[];
        extern uint8_t __dtb_testcases_end[];
        const int size = __dtb_testcases_end - __dtb_testcases_begin;
@@ -885,27 +885,27 @@ static int __init selftest_data_add(void)
        }
 
        /* creating copy */
-       selftest_data = kmemdup(__dtb_testcases_begin, size, GFP_KERNEL);
+       unittest_data = kmemdup(__dtb_testcases_begin, size, GFP_KERNEL);
 
-       if (!selftest_data) {
-               pr_warn("%s: Failed to allocate memory for selftest_data; "
+       if (!unittest_data) {
+               pr_warn("%s: Failed to allocate memory for unittest_data; "
                        "not running tests\n", __func__);
                return -ENOMEM;
        }
-       of_fdt_unflatten_tree(selftest_data, &selftest_data_node);
-       if (!selftest_data_node) {
+       of_fdt_unflatten_tree(unittest_data, &unittest_data_node);
+       if (!unittest_data_node) {
                pr_warn("%s: No tree to attach; not running tests\n", __func__);
                return -ENODATA;
        }
-       of_node_set_flag(selftest_data_node, OF_DETACHED);
-       rc = of_resolve_phandles(selftest_data_node);
+       of_node_set_flag(unittest_data_node, OF_DETACHED);
+       rc = of_resolve_phandles(unittest_data_node);
        if (rc) {
                pr_err("%s: Failed to resolve phandles (rc=%i)\n", __func__, rc);
                return -EINVAL;
        }
 
        if (!of_root) {
-               of_root = selftest_data_node;
+               of_root = unittest_data_node;
                for_each_of_allnodes(np)
                        __of_attach_node_sysfs(np);
                of_aliases = of_find_node_by_path("/aliases");
@@ -914,7 +914,7 @@ static int __init selftest_data_add(void)
        }
 
        /* attach the sub-tree to live tree */
-       np = selftest_data_node->child;
+       np = unittest_data_node->child;
        while (np) {
                struct device_node *next = np->sibling;
                np->parent = of_root;
@@ -926,7 +926,7 @@ static int __init selftest_data_add(void)
 
 #ifdef CONFIG_OF_OVERLAY
 
-static int selftest_probe(struct platform_device *pdev)
+static int unittest_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
@@ -944,7 +944,7 @@ static int selftest_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int selftest_remove(struct platform_device *pdev)
+static int unittest_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
@@ -953,18 +953,18 @@ static int selftest_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct of_device_id selftest_match[] = {
-       { .compatible = "selftest", },
+static struct of_device_id unittest_match[] = {
+       { .compatible = "unittest", },
        {},
 };
 
-static struct platform_driver selftest_driver = {
-       .probe                  = selftest_probe,
-       .remove                 = selftest_remove,
+static struct platform_driver unittest_driver = {
+       .probe                  = unittest_probe,
+       .remove                 = unittest_remove,
        .driver = {
-               .name           = "selftest",
+               .name           = "unittest",
                .owner          = THIS_MODULE,
-               .of_match_table = of_match_ptr(selftest_match),
+               .of_match_table = of_match_ptr(unittest_match),
        },
 };
 
@@ -1046,7 +1046,7 @@ static int of_path_device_type_exists(const char *path,
        return 0;
 }
 
-static const char *selftest_path(int nr, enum overlay_type ovtype)
+static const char *unittest_path(int nr, enum overlay_type ovtype)
 {
        const char *base;
        static char buf[256];
@@ -1062,16 +1062,16 @@ static const char *selftest_path(int nr, enum overlay_type ovtype)
                buf[0] = '\0';
                return buf;
        }
-       snprintf(buf, sizeof(buf) - 1, "%s/test-selftest%d", base, nr);
+       snprintf(buf, sizeof(buf) - 1, "%s/test-unittest%d", base, nr);
        buf[sizeof(buf) - 1] = '\0';
        return buf;
 }
 
-static int of_selftest_device_exists(int selftest_nr, enum overlay_type ovtype)
+static int of_unittest_device_exists(int unittest_nr, enum overlay_type ovtype)
 {
        const char *path;
 
-       path = selftest_path(selftest_nr, ovtype);
+       path = unittest_path(unittest_nr, ovtype);
 
        switch (ovtype) {
        case PDEV_OVERLAY:
@@ -1095,7 +1095,7 @@ static const char *overlay_path(int nr)
 
 static const char *bus_path = "/testcase-data/overlay-node/test-bus";
 
-static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr,
+static int of_unittest_apply_overlay(int unittest_nr, int overlay_nr,
                int *overlay_id)
 {
        struct device_node *np = NULL;
@@ -1103,7 +1103,7 @@ static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr,
 
        np = of_find_node_by_path(overlay_path(overlay_nr));
        if (np == NULL) {
-               selftest(0, "could not find overlay node @\"%s\"\n",
+               unittest(0, "could not find overlay node @\"%s\"\n",
                                overlay_path(overlay_nr));
                ret = -EINVAL;
                goto out;
@@ -1111,7 +1111,7 @@ static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr,
 
        ret = of_overlay_create(np);
        if (ret < 0) {
-               selftest(0, "could not create overlay from \"%s\"\n",
+               unittest(0, "could not create overlay from \"%s\"\n",
                                overlay_path(overlay_nr));
                goto out;
        }
@@ -1129,31 +1129,31 @@ out:
 }
 
 /* apply an overlay while checking before and after states */
-static int of_selftest_apply_overlay_check(int overlay_nr, int selftest_nr,
+static int of_unittest_apply_overlay_check(int overlay_nr, int unittest_nr,
                int before, int after, enum overlay_type ovtype)
 {
        int ret;
 
-       /* selftest device must not be in before state */
-       if (of_selftest_device_exists(selftest_nr, ovtype) != before) {
-               selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+       /* unittest device must not be in before state */
+       if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
+               unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
                                overlay_path(overlay_nr),
-                               selftest_path(selftest_nr, ovtype),
+                               unittest_path(unittest_nr, ovtype),
                                !before ? "enabled" : "disabled");
                return -EINVAL;
        }
 
-       ret = of_selftest_apply_overlay(overlay_nr, selftest_nr, NULL);
+       ret = of_unittest_apply_overlay(overlay_nr, unittest_nr, NULL);
        if (ret != 0) {
-               /* of_selftest_apply_overlay already called selftest() */
+               /* of_unittest_apply_overlay already called unittest() */
                return ret;
        }
 
-       /* selftest device must be to set to after state */
-       if (of_selftest_device_exists(selftest_nr, ovtype) != after) {
-               selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
+       /* unittest device must be to set to after state */
+       if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
+               unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
                                overlay_path(overlay_nr),
-                               selftest_path(selftest_nr, ovtype),
+                               unittest_path(unittest_nr, ovtype),
                                !after ? "enabled" : "disabled");
                return -EINVAL;
        }
@@ -1162,50 +1162,50 @@ static int of_selftest_apply_overlay_check(int overlay_nr, int selftest_nr,
 }
 
 /* apply an overlay and then revert it while checking before, after states */
-static int of_selftest_apply_revert_overlay_check(int overlay_nr,
-               int selftest_nr, int before, int after,
+static int of_unittest_apply_revert_overlay_check(int overlay_nr,
+               int unittest_nr, int before, int after,
                enum overlay_type ovtype)
 {
        int ret, ov_id;
 
-       /* selftest device must be in before state */
-       if (of_selftest_device_exists(selftest_nr, ovtype) != before) {
-               selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+       /* unittest device must be in before state */
+       if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
+               unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
                                overlay_path(overlay_nr),
-                               selftest_path(selftest_nr, ovtype),
+                               unittest_path(unittest_nr, ovtype),
                                !before ? "enabled" : "disabled");
                return -EINVAL;
        }
 
        /* apply the overlay */
-       ret = of_selftest_apply_overlay(overlay_nr, selftest_nr, &ov_id);
+       ret = of_unittest_apply_overlay(overlay_nr, unittest_nr, &ov_id);
        if (ret != 0) {
-               /* of_selftest_apply_overlay already called selftest() */
+               /* of_unittest_apply_overlay already called unittest() */
                return ret;
        }
 
-       /* selftest device must be in after state */
-       if (of_selftest_device_exists(selftest_nr, ovtype) != after) {
-               selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
+       /* unittest device must be in after state */
+       if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
+               unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
                                overlay_path(overlay_nr),
-                               selftest_path(selftest_nr, ovtype),
+                               unittest_path(unittest_nr, ovtype),
                                !after ? "enabled" : "disabled");
                return -EINVAL;
        }
 
        ret = of_overlay_destroy(ov_id);
        if (ret != 0) {
-               selftest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n",
+               unittest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n",
                                overlay_path(overlay_nr),
-                               selftest_path(selftest_nr, ovtype));
+                               unittest_path(unittest_nr, ovtype));
                return ret;
        }
 
-       /* selftest device must be again in before state */
-       if (of_selftest_device_exists(selftest_nr, PDEV_OVERLAY) != before) {
-               selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+       /* unittest device must be again in before state */
+       if (of_unittest_device_exists(unittest_nr, PDEV_OVERLAY) != before) {
+               unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
                                overlay_path(overlay_nr),
-                               selftest_path(selftest_nr, ovtype),
+                               unittest_path(unittest_nr, ovtype),
                                !before ? "enabled" : "disabled");
                return -EINVAL;
        }
@@ -1214,98 +1214,98 @@ static int of_selftest_apply_revert_overlay_check(int overlay_nr,
 }
 
 /* test activation of device */
-static void of_selftest_overlay_0(void)
+static void of_unittest_overlay_0(void)
 {
        int ret;
 
        /* device should enable */
-       ret = of_selftest_apply_overlay_check(0, 0, 0, 1, PDEV_OVERLAY);
+       ret = of_unittest_apply_overlay_check(0, 0, 0, 1, PDEV_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 0);
+       unittest(1, "overlay test %d passed\n", 0);
 }
 
 /* test deactivation of device */
-static void of_selftest_overlay_1(void)
+static void of_unittest_overlay_1(void)
 {
        int ret;
 
        /* device should disable */
-       ret = of_selftest_apply_overlay_check(1, 1, 1, 0, PDEV_OVERLAY);
+       ret = of_unittest_apply_overlay_check(1, 1, 1, 0, PDEV_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 1);
+       unittest(1, "overlay test %d passed\n", 1);
 }
 
 /* test activation of device */
-static void of_selftest_overlay_2(void)
+static void of_unittest_overlay_2(void)
 {
        int ret;
 
        /* device should enable */
-       ret = of_selftest_apply_overlay_check(2, 2, 0, 1, PDEV_OVERLAY);
+       ret = of_unittest_apply_overlay_check(2, 2, 0, 1, PDEV_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 2);
+       unittest(1, "overlay test %d passed\n", 2);
 }
 
 /* test deactivation of device */
-static void of_selftest_overlay_3(void)
+static void of_unittest_overlay_3(void)
 {
        int ret;
 
        /* device should disable */
-       ret = of_selftest_apply_overlay_check(3, 3, 1, 0, PDEV_OVERLAY);
+       ret = of_unittest_apply_overlay_check(3, 3, 1, 0, PDEV_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 3);
+       unittest(1, "overlay test %d passed\n", 3);
 }
 
 /* test activation of a full device node */
-static void of_selftest_overlay_4(void)
+static void of_unittest_overlay_4(void)
 {
        int ret;
 
        /* device should disable */
-       ret = of_selftest_apply_overlay_check(4, 4, 0, 1, PDEV_OVERLAY);
+       ret = of_unittest_apply_overlay_check(4, 4, 0, 1, PDEV_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 4);
+       unittest(1, "overlay test %d passed\n", 4);
 }
 
 /* test overlay apply/revert sequence */
-static void of_selftest_overlay_5(void)
+static void of_unittest_overlay_5(void)
 {
        int ret;
 
        /* device should disable */
-       ret = of_selftest_apply_revert_overlay_check(5, 5, 0, 1, PDEV_OVERLAY);
+       ret = of_unittest_apply_revert_overlay_check(5, 5, 0, 1, PDEV_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 5);
+       unittest(1, "overlay test %d passed\n", 5);
 }
 
 /* test overlay application in sequence */
-static void of_selftest_overlay_6(void)
+static void of_unittest_overlay_6(void)
 {
        struct device_node *np;
        int ret, i, ov_id[2];
-       int overlay_nr = 6, selftest_nr = 6;
+       int overlay_nr = 6, unittest_nr = 6;
        int before = 0, after = 1;
 
-       /* selftest device must be in before state */
+       /* unittest device must be in before state */
        for (i = 0; i < 2; i++) {
-               if (of_selftest_device_exists(selftest_nr + i, PDEV_OVERLAY)
+               if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY)
                                != before) {
-                       selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+                       unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
                                        overlay_path(overlay_nr + i),
-                                       selftest_path(selftest_nr + i,
+                                       unittest_path(unittest_nr + i,
                                                PDEV_OVERLAY),
                                        !before ? "enabled" : "disabled");
                        return;
@@ -1317,14 +1317,14 @@ static void of_selftest_overlay_6(void)
 
                np = of_find_node_by_path(overlay_path(overlay_nr + i));
                if (np == NULL) {
-                       selftest(0, "could not find overlay node @\"%s\"\n",
+                       unittest(0, "could not find overlay node @\"%s\"\n",
                                        overlay_path(overlay_nr + i));
                        return;
                }
 
                ret = of_overlay_create(np);
                if (ret < 0)  {
-                       selftest(0, "could not create overlay from \"%s\"\n",
+                       unittest(0, "could not create overlay from \"%s\"\n",
                                        overlay_path(overlay_nr + i));
                        return;
                }
@@ -1332,12 +1332,12 @@ static void of_selftest_overlay_6(void)
        }
 
        for (i = 0; i < 2; i++) {
-               /* selftest device must be in after state */
-               if (of_selftest_device_exists(selftest_nr + i, PDEV_OVERLAY)
+               /* unittest device must be in after state */
+               if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY)
                                != after) {
-                       selftest(0, "overlay @\"%s\" failed @\"%s\" %s\n",
+                       unittest(0, "overlay @\"%s\" failed @\"%s\" %s\n",
                                        overlay_path(overlay_nr + i),
-                                       selftest_path(selftest_nr + i,
+                                       unittest_path(unittest_nr + i,
                                                PDEV_OVERLAY),
                                        !after ? "enabled" : "disabled");
                        return;
@@ -1347,36 +1347,36 @@ static void of_selftest_overlay_6(void)
        for (i = 1; i >= 0; i--) {
                ret = of_overlay_destroy(ov_id[i]);
                if (ret != 0) {
-                       selftest(0, "overlay @\"%s\" failed destroy @\"%s\"\n",
+                       unittest(0, "overlay @\"%s\" failed destroy @\"%s\"\n",
                                        overlay_path(overlay_nr + i),
-                                       selftest_path(selftest_nr + i,
+                                       unittest_path(unittest_nr + i,
                                                PDEV_OVERLAY));
                        return;
                }
        }
 
        for (i = 0; i < 2; i++) {
-               /* selftest device must be again in before state */
-               if (of_selftest_device_exists(selftest_nr + i, PDEV_OVERLAY)
+               /* unittest device must be again in before state */
+               if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY)
                                != before) {
-                       selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+                       unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
                                        overlay_path(overlay_nr + i),
-                                       selftest_path(selftest_nr + i,
+                                       unittest_path(unittest_nr + i,
                                                PDEV_OVERLAY),
                                        !before ? "enabled" : "disabled");
                        return;
                }
        }
 
-       selftest(1, "overlay test %d passed\n", 6);
+       unittest(1, "overlay test %d passed\n", 6);
 }
 
 /* test overlay application in sequence */
-static void of_selftest_overlay_8(void)
+static void of_unittest_overlay_8(void)
 {
        struct device_node *np;
        int ret, i, ov_id[2];
-       int overlay_nr = 8, selftest_nr = 8;
+       int overlay_nr = 8, unittest_nr = 8;
 
        /* we don't care about device state in this test */
 
@@ -1385,14 +1385,14 @@ static void of_selftest_overlay_8(void)
 
                np = of_find_node_by_path(overlay_path(overlay_nr + i));
                if (np == NULL) {
-                       selftest(0, "could not find overlay node @\"%s\"\n",
+                       unittest(0, "could not find overlay node @\"%s\"\n",
                                        overlay_path(overlay_nr + i));
                        return;
                }
 
                ret = of_overlay_create(np);
                if (ret < 0)  {
-                       selftest(0, "could not create overlay from \"%s\"\n",
+                       unittest(0, "could not create overlay from \"%s\"\n",
                                        overlay_path(overlay_nr + i));
                        return;
                }
@@ -1402,9 +1402,9 @@ static void of_selftest_overlay_8(void)
        /* now try to remove first overlay (it should fail) */
        ret = of_overlay_destroy(ov_id[0]);
        if (ret == 0) {
-               selftest(0, "overlay @\"%s\" was destroyed @\"%s\"\n",
+               unittest(0, "overlay @\"%s\" was destroyed @\"%s\"\n",
                                overlay_path(overlay_nr + 0),
-                               selftest_path(selftest_nr,
+                               unittest_path(unittest_nr,
                                        PDEV_OVERLAY));
                return;
        }
@@ -1413,85 +1413,85 @@ static void of_selftest_overlay_8(void)
        for (i = 1; i >= 0; i--) {
                ret = of_overlay_destroy(ov_id[i]);
                if (ret != 0) {
-                       selftest(0, "overlay @\"%s\" not destroyed @\"%s\"\n",
+                       unittest(0, "overlay @\"%s\" not destroyed @\"%s\"\n",
                                        overlay_path(overlay_nr + i),
-                                       selftest_path(selftest_nr,
+                                       unittest_path(unittest_nr,
                                                PDEV_OVERLAY));
                        return;
                }
        }
 
-       selftest(1, "overlay test %d passed\n", 8);
+       unittest(1, "overlay test %d passed\n", 8);
 }
 
 /* test insertion of a bus with parent devices */
-static void of_selftest_overlay_10(void)
+static void of_unittest_overlay_10(void)
 {
        int ret;
        char *child_path;
 
        /* device should disable */
-       ret = of_selftest_apply_overlay_check(10, 10, 0, 1, PDEV_OVERLAY);
-       if (selftest(ret == 0,
+       ret = of_unittest_apply_overlay_check(10, 10, 0, 1, PDEV_OVERLAY);
+       if (unittest(ret == 0,
                        "overlay test %d failed; overlay application\n", 10))
                return;
 
-       child_path = kasprintf(GFP_KERNEL, "%s/test-selftest101",
-                       selftest_path(10, PDEV_OVERLAY));
-       if (selftest(child_path, "overlay test %d failed; kasprintf\n", 10))
+       child_path = kasprintf(GFP_KERNEL, "%s/test-unittest101",
+                       unittest_path(10, PDEV_OVERLAY));
+       if (unittest(child_path, "overlay test %d failed; kasprintf\n", 10))
                return;
 
        ret = of_path_device_type_exists(child_path, PDEV_OVERLAY);
        kfree(child_path);
-       if (selftest(ret, "overlay test %d failed; no child device\n", 10))
+       if (unittest(ret, "overlay test %d failed; no child device\n", 10))
                return;
 }
 
 /* test insertion of a bus with parent devices (and revert) */
-static void of_selftest_overlay_11(void)
+static void of_unittest_overlay_11(void)
 {
        int ret;
 
        /* device should disable */
-       ret = of_selftest_apply_revert_overlay_check(11, 11, 0, 1,
+       ret = of_unittest_apply_revert_overlay_check(11, 11, 0, 1,
                        PDEV_OVERLAY);
-       if (selftest(ret == 0,
+       if (unittest(ret == 0,
                        "overlay test %d failed; overlay application\n", 11))
                return;
 }
 
 #if IS_BUILTIN(CONFIG_I2C) && IS_ENABLED(CONFIG_OF_OVERLAY)
 
-struct selftest_i2c_bus_data {
+struct unittest_i2c_bus_data {
        struct platform_device  *pdev;
        struct i2c_adapter      adap;
 };
 
-static int selftest_i2c_master_xfer(struct i2c_adapter *adap,
+static int unittest_i2c_master_xfer(struct i2c_adapter *adap,
                struct i2c_msg *msgs, int num)
 {
-       struct selftest_i2c_bus_data *std = i2c_get_adapdata(adap);
+       struct unittest_i2c_bus_data *std = i2c_get_adapdata(adap);
 
        (void)std;
 
        return num;
 }
 
-static u32 selftest_i2c_functionality(struct i2c_adapter *adap)
+static u32 unittest_i2c_functionality(struct i2c_adapter *adap)
 {
        return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
 }
 
-static const struct i2c_algorithm selftest_i2c_algo = {
-       .master_xfer    = selftest_i2c_master_xfer,
-       .functionality  = selftest_i2c_functionality,
+static const struct i2c_algorithm unittest_i2c_algo = {
+       .master_xfer    = unittest_i2c_master_xfer,
+       .functionality  = unittest_i2c_functionality,
 };
 
-static int selftest_i2c_bus_probe(struct platform_device *pdev)
+static int unittest_i2c_bus_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
-       struct selftest_i2c_bus_data *std;
+       struct unittest_i2c_bus_data *std;
        struct i2c_adapter *adap;
        int ret;
 
@@ -1505,7 +1505,7 @@ static int selftest_i2c_bus_probe(struct platform_device *pdev)
 
        std = devm_kzalloc(dev, sizeof(*std), GFP_KERNEL);
        if (!std) {
-               dev_err(dev, "Failed to allocate selftest i2c data\n");
+               dev_err(dev, "Failed to allocate unittest i2c data\n");
                return -ENOMEM;
        }
 
@@ -1518,7 +1518,7 @@ static int selftest_i2c_bus_probe(struct platform_device *pdev)
        adap->nr = -1;
        strlcpy(adap->name, pdev->name, sizeof(adap->name));
        adap->class = I2C_CLASS_DEPRECATED;
-       adap->algo = &selftest_i2c_algo;
+       adap->algo = &unittest_i2c_algo;
        adap->dev.parent = dev;
        adap->dev.of_node = dev->of_node;
        adap->timeout = 5 * HZ;
@@ -1533,11 +1533,11 @@ static int selftest_i2c_bus_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int selftest_i2c_bus_remove(struct platform_device *pdev)
+static int unittest_i2c_bus_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
-       struct selftest_i2c_bus_data *std = platform_get_drvdata(pdev);
+       struct unittest_i2c_bus_data *std = platform_get_drvdata(pdev);
 
        dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
        i2c_del_adapter(&std->adap);
@@ -1545,21 +1545,21 @@ static int selftest_i2c_bus_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct of_device_id selftest_i2c_bus_match[] = {
-       { .compatible = "selftest-i2c-bus", },
+static struct of_device_id unittest_i2c_bus_match[] = {
+       { .compatible = "unittest-i2c-bus", },
        {},
 };
 
-static struct platform_driver selftest_i2c_bus_driver = {
-       .probe                  = selftest_i2c_bus_probe,
-       .remove                 = selftest_i2c_bus_remove,
+static struct platform_driver unittest_i2c_bus_driver = {
+       .probe                  = unittest_i2c_bus_probe,
+       .remove                 = unittest_i2c_bus_remove,
        .driver = {
-               .name           = "selftest-i2c-bus",
-               .of_match_table = of_match_ptr(selftest_i2c_bus_match),
+               .name           = "unittest-i2c-bus",
+               .of_match_table = of_match_ptr(unittest_i2c_bus_match),
        },
 };
 
-static int selftest_i2c_dev_probe(struct i2c_client *client,
+static int unittest_i2c_dev_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
        struct device *dev = &client->dev;
@@ -1575,7 +1575,7 @@ static int selftest_i2c_dev_probe(struct i2c_client *client,
        return 0;
 };
 
-static int selftest_i2c_dev_remove(struct i2c_client *client)
+static int unittest_i2c_dev_remove(struct i2c_client *client)
 {
        struct device *dev = &client->dev;
        struct device_node *np = client->dev.of_node;
@@ -1584,42 +1584,42 @@ static int selftest_i2c_dev_remove(struct i2c_client *client)
        return 0;
 }
 
-static const struct i2c_device_id selftest_i2c_dev_id[] = {
-       { .name = "selftest-i2c-dev" },
+static const struct i2c_device_id unittest_i2c_dev_id[] = {
+       { .name = "unittest-i2c-dev" },
        { }
 };
 
-static struct i2c_driver selftest_i2c_dev_driver = {
+static struct i2c_driver unittest_i2c_dev_driver = {
        .driver = {
-               .name = "selftest-i2c-dev",
+               .name = "unittest-i2c-dev",
                .owner = THIS_MODULE,
        },
-       .probe = selftest_i2c_dev_probe,
-       .remove = selftest_i2c_dev_remove,
-       .id_table = selftest_i2c_dev_id,
+       .probe = unittest_i2c_dev_probe,
+       .remove = unittest_i2c_dev_remove,
+       .id_table = unittest_i2c_dev_id,
 };
 
 #if IS_BUILTIN(CONFIG_I2C_MUX)
 
-struct selftest_i2c_mux_data {
+struct unittest_i2c_mux_data {
        int nchans;
        struct i2c_adapter *adap[];
 };
 
-static int selftest_i2c_mux_select_chan(struct i2c_adapter *adap,
+static int unittest_i2c_mux_select_chan(struct i2c_adapter *adap,
                               void *client, u32 chan)
 {
        return 0;
 }
 
-static int selftest_i2c_mux_probe(struct i2c_client *client,
+static int unittest_i2c_mux_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
        int ret, i, nchans, size;
        struct device *dev = &client->dev;
        struct i2c_adapter *adap = to_i2c_adapter(dev->parent);
        struct device_node *np = client->dev.of_node, *child;
-       struct selftest_i2c_mux_data *stm;
+       struct unittest_i2c_mux_data *stm;
        u32 reg, max_reg;
 
        dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
@@ -1643,7 +1643,7 @@ static int selftest_i2c_mux_probe(struct i2c_client *client,
                return -EINVAL;
        }
 
-       size = offsetof(struct selftest_i2c_mux_data, adap[nchans]);
+       size = offsetof(struct unittest_i2c_mux_data, adap[nchans]);
        stm = devm_kzalloc(dev, size, GFP_KERNEL);
        if (!stm) {
                dev_err(dev, "Out of memory\n");
@@ -1652,7 +1652,7 @@ static int selftest_i2c_mux_probe(struct i2c_client *client,
        stm->nchans = nchans;
        for (i = 0; i < nchans; i++) {
                stm->adap[i] = i2c_add_mux_adapter(adap, dev, client,
-                               0, i, 0, selftest_i2c_mux_select_chan, NULL);
+                               0, i, 0, unittest_i2c_mux_select_chan, NULL);
                if (!stm->adap[i]) {
                        dev_err(dev, "Failed to register mux #%d\n", i);
                        for (i--; i >= 0; i--)
@@ -1666,11 +1666,11 @@ static int selftest_i2c_mux_probe(struct i2c_client *client,
        return 0;
 };
 
-static int selftest_i2c_mux_remove(struct i2c_client *client)
+static int unittest_i2c_mux_remove(struct i2c_client *client)
 {
        struct device *dev = &client->dev;
        struct device_node *np = client->dev.of_node;
-       struct selftest_i2c_mux_data *stm = i2c_get_clientdata(client);
+       struct unittest_i2c_mux_data *stm = i2c_get_clientdata(client);
        int i;
 
        dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
@@ -1679,166 +1679,166 @@ static int selftest_i2c_mux_remove(struct i2c_client *client)
        return 0;
 }
 
-static const struct i2c_device_id selftest_i2c_mux_id[] = {
-       { .name = "selftest-i2c-mux" },
+static const struct i2c_device_id unittest_i2c_mux_id[] = {
+       { .name = "unittest-i2c-mux" },
        { }
 };
 
-static struct i2c_driver selftest_i2c_mux_driver = {
+static struct i2c_driver unittest_i2c_mux_driver = {
        .driver = {
-               .name = "selftest-i2c-mux",
+               .name = "unittest-i2c-mux",
                .owner = THIS_MODULE,
        },
-       .probe = selftest_i2c_mux_probe,
-       .remove = selftest_i2c_mux_remove,
-       .id_table = selftest_i2c_mux_id,
+       .probe = unittest_i2c_mux_probe,
+       .remove = unittest_i2c_mux_remove,
+       .id_table = unittest_i2c_mux_id,
 };
 
 #endif
 
-static int of_selftest_overlay_i2c_init(void)
+static int of_unittest_overlay_i2c_init(void)
 {
        int ret;
 
-       ret = i2c_add_driver(&selftest_i2c_dev_driver);
-       if (selftest(ret == 0,
-                       "could not register selftest i2c device driver\n"))
+       ret = i2c_add_driver(&unittest_i2c_dev_driver);
+       if (unittest(ret == 0,
+                       "could not register unittest i2c device driver\n"))
                return ret;
 
-       ret = platform_driver_register(&selftest_i2c_bus_driver);
-       if (selftest(ret == 0,
-                       "could not register selftest i2c bus driver\n"))
+       ret = platform_driver_register(&unittest_i2c_bus_driver);
+       if (unittest(ret == 0,
+                       "could not register unittest i2c bus driver\n"))
                return ret;
 
 #if IS_BUILTIN(CONFIG_I2C_MUX)
-       ret = i2c_add_driver(&selftest_i2c_mux_driver);
-       if (selftest(ret == 0,
-                       "could not register selftest i2c mux driver\n"))
+       ret = i2c_add_driver(&unittest_i2c_mux_driver);
+       if (unittest(ret == 0,
+                       "could not register unittest i2c mux driver\n"))
                return ret;
 #endif
 
        return 0;
 }
 
-static void of_selftest_overlay_i2c_cleanup(void)
+static void of_unittest_overlay_i2c_cleanup(void)
 {
 #if IS_BUILTIN(CONFIG_I2C_MUX)
-       i2c_del_driver(&selftest_i2c_mux_driver);
+       i2c_del_driver(&unittest_i2c_mux_driver);
 #endif
-       platform_driver_unregister(&selftest_i2c_bus_driver);
-       i2c_del_driver(&selftest_i2c_dev_driver);
+       platform_driver_unregister(&unittest_i2c_bus_driver);
+       i2c_del_driver(&unittest_i2c_dev_driver);
 }
 
-static void of_selftest_overlay_i2c_12(void)
+static void of_unittest_overlay_i2c_12(void)
 {
        int ret;
 
        /* device should enable */
-       ret = of_selftest_apply_overlay_check(12, 12, 0, 1, I2C_OVERLAY);
+       ret = of_unittest_apply_overlay_check(12, 12, 0, 1, I2C_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 12);
+       unittest(1, "overlay test %d passed\n", 12);
 }
 
 /* test deactivation of device */
-static void of_selftest_overlay_i2c_13(void)
+static void of_unittest_overlay_i2c_13(void)
 {
        int ret;
 
        /* device should disable */
-       ret = of_selftest_apply_overlay_check(13, 13, 1, 0, I2C_OVERLAY);
+       ret = of_unittest_apply_overlay_check(13, 13, 1, 0, I2C_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 13);
+       unittest(1, "overlay test %d passed\n", 13);
 }
 
 /* just check for i2c mux existence */
-static void of_selftest_overlay_i2c_14(void)
+static void of_unittest_overlay_i2c_14(void)
 {
 }
 
-static void of_selftest_overlay_i2c_15(void)
+static void of_unittest_overlay_i2c_15(void)
 {
        int ret;
 
        /* device should enable */
-       ret = of_selftest_apply_overlay_check(16, 15, 0, 1, I2C_OVERLAY);
+       ret = of_unittest_apply_overlay_check(16, 15, 0, 1, I2C_OVERLAY);
        if (ret != 0)
                return;
 
-       selftest(1, "overlay test %d passed\n", 15);
+       unittest(1, "overlay test %d passed\n", 15);
 }
 
 #else
 
-static inline void of_selftest_overlay_i2c_14(void) { }
-static inline void of_selftest_overlay_i2c_15(void) { }
+static inline void of_unittest_overlay_i2c_14(void) { }
+static inline void of_unittest_overlay_i2c_15(void) { }
 
 #endif
 
-static void __init of_selftest_overlay(void)
+static void __init of_unittest_overlay(void)
 {
        struct device_node *bus_np = NULL;
        int ret;
 
-       ret = platform_driver_register(&selftest_driver);
+       ret = platform_driver_register(&unittest_driver);
        if (ret != 0) {
-               selftest(0, "could not register selftest driver\n");
+               unittest(0, "could not register unittest driver\n");
                goto out;
        }
 
        bus_np = of_find_node_by_path(bus_path);
        if (bus_np == NULL) {
-               selftest(0, "could not find bus_path \"%s\"\n", bus_path);
+               unittest(0, "could not find bus_path \"%s\"\n", bus_path);
                goto out;
        }
 
        ret = of_platform_populate(bus_np, of_default_bus_match_table,
                        NULL, NULL);
        if (ret != 0) {
-               selftest(0, "could not populate bus @ \"%s\"\n", bus_path);
+               unittest(0, "could not populate bus @ \"%s\"\n", bus_path);
                goto out;
        }
 
-       if (!of_selftest_device_exists(100, PDEV_OVERLAY)) {
-               selftest(0, "could not find selftest0 @ \"%s\"\n",
-                               selftest_path(100, PDEV_OVERLAY));
+       if (!of_unittest_device_exists(100, PDEV_OVERLAY)) {
+               unittest(0, "could not find unittest0 @ \"%s\"\n",
+                               unittest_path(100, PDEV_OVERLAY));
                goto out;
        }
 
-       if (of_selftest_device_exists(101, PDEV_OVERLAY)) {
-               selftest(0, "selftest1 @ \"%s\" should not exist\n",
-                               selftest_path(101, PDEV_OVERLAY));
+       if (of_unittest_device_exists(101, PDEV_OVERLAY)) {
+               unittest(0, "unittest1 @ \"%s\" should not exist\n",
+                               unittest_path(101, PDEV_OVERLAY));
                goto out;
        }
 
-       selftest(1, "basic infrastructure of overlays passed");
+       unittest(1, "basic infrastructure of overlays passed");
 
        /* tests in sequence */
-       of_selftest_overlay_0();
-       of_selftest_overlay_1();
-       of_selftest_overlay_2();
-       of_selftest_overlay_3();
-       of_selftest_overlay_4();
-       of_selftest_overlay_5();
-       of_selftest_overlay_6();
-       of_selftest_overlay_8();
-
-       of_selftest_overlay_10();
-       of_selftest_overlay_11();
+       of_unittest_overlay_0();
+       of_unittest_overlay_1();
+       of_unittest_overlay_2();
+       of_unittest_overlay_3();
+       of_unittest_overlay_4();
+       of_unittest_overlay_5();
+       of_unittest_overlay_6();
+       of_unittest_overlay_8();
+
+       of_unittest_overlay_10();
+       of_unittest_overlay_11();
 
 #if IS_BUILTIN(CONFIG_I2C)
-       if (selftest(of_selftest_overlay_i2c_init() == 0, "i2c init failed\n"))
+       if (unittest(of_unittest_overlay_i2c_init() == 0, "i2c init failed\n"))
                goto out;
 
-       of_selftest_overlay_i2c_12();
-       of_selftest_overlay_i2c_13();
-       of_selftest_overlay_i2c_14();
-       of_selftest_overlay_i2c_15();
+       of_unittest_overlay_i2c_12();
+       of_unittest_overlay_i2c_13();
+       of_unittest_overlay_i2c_14();
+       of_unittest_overlay_i2c_15();
 
-       of_selftest_overlay_i2c_cleanup();
+       of_unittest_overlay_i2c_cleanup();
 #endif
 
 out:
@@ -1846,16 +1846,16 @@ out:
 }
 
 #else
-static inline void __init of_selftest_overlay(void) { }
+static inline void __init of_unittest_overlay(void) { }
 #endif
 
-static int __init of_selftest(void)
+static int __init of_unittest(void)
 {
        struct device_node *np;
        int res;
 
-       /* adding data for selftest */
-       res = selftest_data_add();
+       /* adding data for unittest */
+       res = unittest_data_add();
        if (res)
                return res;
        if (!of_aliases)
@@ -1868,27 +1868,27 @@ static int __init of_selftest(void)
        }
        of_node_put(np);
 
-       pr_info("start of selftest - you will see error messages\n");
-       of_selftest_check_tree_linkage();
-       of_selftest_check_phandles();
-       of_selftest_find_node_by_name();
-       of_selftest_dynamic();
-       of_selftest_parse_phandle_with_args();
-       of_selftest_property_string();
-       of_selftest_property_copy();
-       of_selftest_changeset();
-       of_selftest_parse_interrupts();
-       of_selftest_parse_interrupts_extended();
-       of_selftest_match_node();
-       of_selftest_platform_populate();
-       of_selftest_overlay();
+       pr_info("start of unittest - you will see error messages\n");
+       of_unittest_check_tree_linkage();
+       of_unittest_check_phandles();
+       of_unittest_find_node_by_name();
+       of_unittest_dynamic();
+       of_unittest_parse_phandle_with_args();
+       of_unittest_property_string();
+       of_unittest_property_copy();
+       of_unittest_changeset();
+       of_unittest_parse_interrupts();
+       of_unittest_parse_interrupts_extended();
+       of_unittest_match_node();
+       of_unittest_platform_populate();
+       of_unittest_overlay();
 
        /* Double check linkage after removing testcase data */
-       of_selftest_check_tree_linkage();
+       of_unittest_check_tree_linkage();
 
-       pr_info("end of selftest - %i passed, %i failed\n",
-               selftest_results.passed, selftest_results.failed);
+       pr_info("end of unittest - %i passed, %i failed\n",
+               unittest_results.passed, unittest_results.failed);
 
        return 0;
 }
-late_initcall(of_selftest);
+late_initcall(of_unittest);
index 24183028bd712b11af46cd4531f60b33b4e57338..6d5b38d6957852ee81caa09cb6e3c047c55d26b8 100644 (file)
@@ -38,6 +38,7 @@ config IIO_SIMPLE_DUMMY_EVENTS
 config IIO_SIMPLE_DUMMY_BUFFER
        bool "Buffered capture support"
        select IIO_BUFFER
+       select IIO_TRIGGER
        select IIO_KFIFO_BUF
        help
          Add buffered data capture to the simple dummy driver.
index fd171d8b38fbcc444f3e7118bb66b2d51bdf698c..90cc18b703cf67ae6c089c36d51d8ebde6f28106 100644 (file)
@@ -592,6 +592,7 @@ int hmc5843_common_probe(struct device *dev, struct regmap *regmap,
        mutex_init(&data->lock);
 
        indio_dev->dev.parent = dev;
+       indio_dev->name = dev->driver->name;
        indio_dev->info = &hmc5843_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->channels = data->variant->channels;
index b1893f3f88f1c6b6fdb2e8e42ad565ba23e18fd1..3ad1458bfeb0fc32afe790b2aa0f3e36961b7b45 100644 (file)
@@ -921,6 +921,9 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
        writeb(val | UARTPFIFO_TXFE | UARTPFIFO_RXFE,
                        sport->port.membase + UARTPFIFO);
 
+       /* explicitly clear RDRF */
+       readb(sport->port.membase + UARTSR1);
+
        /* flush Tx and Rx FIFO */
        writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH,
                        sport->port.membase + UARTCFIFO);
@@ -1076,6 +1079,8 @@ static int lpuart_startup(struct uart_port *port)
        sport->txfifo_size = 0x1 << (((temp >> UARTPFIFO_TXSIZE_OFF) &
                UARTPFIFO_FIFOSIZE_MASK) + 1);
 
+       sport->port.fifosize = sport->txfifo_size;
+
        sport->rxfifo_size = 0x1 << (((temp >> UARTPFIFO_RXSIZE_OFF) &
                UARTPFIFO_FIFOSIZE_MASK) + 1);
 
index af821a9087204ec654f637a617513ba06d68a0ef..cf08876922f1446e55a2d8ca79bf87e0d4e24fed 100644 (file)
@@ -963,6 +963,7 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
                        free_irq(ourport->tx_irq, ourport);
                tx_enabled(port) = 0;
                ourport->tx_claimed = 0;
+               ourport->tx_mode = 0;
        }
 
        if (ourport->rx_claimed) {
index a7865c4b04980898b49317386ad6138aab051bc5..0827d7c965276382418f0a602ec5c1412c023142 100644 (file)
@@ -387,6 +387,10 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
                status = PORT_PLC;
                port_change_bit = "link state";
                break;
+       case USB_PORT_FEAT_C_PORT_CONFIG_ERROR:
+               status = PORT_CEC;
+               port_change_bit = "config error";
+               break;
        default:
                /* Should never happen */
                return;
@@ -588,6 +592,8 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
                        status |= USB_PORT_STAT_C_LINK_STATE << 16;
                if ((raw_port_status & PORT_WRC))
                        status |= USB_PORT_STAT_C_BH_RESET << 16;
+               if ((raw_port_status & PORT_CEC))
+                       status |= USB_PORT_STAT_C_CONFIG_ERROR << 16;
        }
 
        if (hcd->speed != HCD_USB3) {
@@ -1005,6 +1011,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                case USB_PORT_FEAT_C_OVER_CURRENT:
                case USB_PORT_FEAT_C_ENABLE:
                case USB_PORT_FEAT_C_PORT_LINK_STATE:
+               case USB_PORT_FEAT_C_PORT_CONFIG_ERROR:
                        xhci_clear_port_change_bit(xhci, wValue, wIndex,
                                        port_array[wIndex], temp);
                        break;
@@ -1069,7 +1076,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
         */
        status = bus_state->resuming_ports;
 
-       mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC;
+       mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC | PORT_CEC;
 
        spin_lock_irqsave(&xhci->lock, flags);
        /* For each port, did anything change?  If so, set that bit in buf. */
index fd53c9ebd662a5fb4593c99ce5dd7c2552ad83c5..2af32e26fafc3727279fe656fbbcaf158736371d 100644 (file)
@@ -115,6 +115,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
        if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
                xhci->quirks |= XHCI_LPM_SUPPORT;
                xhci->quirks |= XHCI_INTEL_HOST;
+               xhci->quirks |= XHCI_AVOID_BEI;
        }
        if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
                        pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) {
@@ -130,7 +131,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                 * PPT chipsets.
                 */
                xhci->quirks |= XHCI_SPURIOUS_REBOOT;
-               xhci->quirks |= XHCI_AVOID_BEI;
        }
        if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
                pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI) {
index f32c292cc8689d81bfce947f7c587603e95c09be..3fc4fe7702533b785bc22ead9fe17939e1f365f8 100644 (file)
@@ -1203,7 +1203,7 @@ static int isp1760_udc_start(struct usb_gadget *gadget,
 
        if (udc->driver) {
                dev_err(udc->isp->dev, "UDC already has a gadget driver\n");
-               spin_unlock(&udc->lock);
+               spin_unlock_irqrestore(&udc->lock, flags);
                return -EBUSY;
        }
 
index 3086dec0ef53bbd5d5d3d21087b91469983492fb..8eb68a31cab6c4021617ca555cd58b086872c112 100644 (file)
@@ -604,6 +604,7 @@ static const struct usb_device_id id_table_combined[] = {
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLXM_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_SYNAPSE_SS200_PID) },
        /*
         * ELV devices:
         */
@@ -1883,8 +1884,12 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial)
 {
        struct usb_device *udev = serial->dev;
 
-       if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) ||
-           (udev->product && !strcmp(udev->product, "BeagleBone/XDS100V2")))
+       if (udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems"))
+               return ftdi_jtag_probe(serial);
+
+       if (udev->product &&
+               (!strcmp(udev->product, "BeagleBone/XDS100V2") ||
+                !strcmp(udev->product, "SNAP Connect E10")))
                return ftdi_jtag_probe(serial);
 
        return 0;
index 56b1b55c4751696b2e89633ea90bfe1c2940c436..4e4f46f3c89c025670d42860756f39b2bb62ae24 100644 (file)
  */
 #define FTDI_NT_ORIONLXM_PID   0x7c90  /* OrionLXm Substation Automation Platform */
 
+/*
+ * Synapse Wireless product ids (FTDI_VID)
+ * http://www.synapse-wireless.com
+ */
+#define FTDI_SYNAPSE_SS200_PID 0x9090 /* SS200 - SNAP Stick 200 */
+
 
 /********************************/
 /** third-party VID/PID combos **/
index dd97d8b572c336e03c7c4c282fbe7e38c44646a4..4f7e072e4e001e9f7c439114f13b52a77d3250d6 100644 (file)
@@ -61,6 +61,7 @@ struct keyspan_pda_private {
 /* For Xircom PGSDB9 and older Entrega version of the same device */
 #define XIRCOM_VENDOR_ID               0x085a
 #define XIRCOM_FAKE_ID                 0x8027
+#define XIRCOM_FAKE_ID_2               0x8025 /* "PGMFHUB" serial */
 #define ENTREGA_VENDOR_ID              0x1645
 #define ENTREGA_FAKE_ID                        0x8093
 
@@ -70,6 +71,7 @@ static const struct usb_device_id id_table_combined[] = {
 #endif
 #ifdef XIRCOM
        { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) },
+       { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) },
        { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) },
 #endif
        { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) },
@@ -93,6 +95,7 @@ static const struct usb_device_id id_table_fake[] = {
 #ifdef XIRCOM
 static const struct usb_device_id id_table_fake_xircom[] = {
        { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) },
+       { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) },
        { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) },
        { }
 };
index 42b87f95267c255f26bce067615607021eca99cd..8b6f6d5fdd68bc442449d4e4d5a5ea1ce9a85f41 100644 (file)
@@ -164,20 +164,15 @@ static void __init omapdss_walk_device(struct device_node *node, bool root)
 
                pn = of_graph_get_remote_port_parent(n);
 
-               if (!pn) {
-                       of_node_put(n);
+               if (!pn)
                        continue;
-               }
 
                if (!of_device_is_available(pn) || omapdss_list_contains(pn)) {
                        of_node_put(pn);
-                       of_node_put(n);
                        continue;
                }
 
                omapdss_walk_device(pn, false);
-
-               of_node_put(n);
        }
 }
 
index b812462083fcaf8d32c215327d28b7c4b7e6e4da..94d96809e686b9ffd1f83c76681c8c3ff0a7cf92 100644 (file)
@@ -55,6 +55,23 @@ config XEN_BALLOON_MEMORY_HOTPLUG
 
          In that case step 3 should be omitted.
 
+config XEN_BALLOON_MEMORY_HOTPLUG_LIMIT
+       int "Hotplugged memory limit (in GiB) for a PV guest"
+       default 512 if X86_64
+       default 4 if X86_32
+       range 0 64 if X86_32
+       depends on XEN_HAVE_PVMMU
+       depends on XEN_BALLOON_MEMORY_HOTPLUG
+       help
+         Maxmium amount of memory (in GiB) that a PV guest can be
+         expanded to when using memory hotplug.
+
+         A PV guest can have more memory than this limit if is
+         started with a larger maximum.
+
+         This value is used to allocate enough space in internal
+         tables needed for physical memory administration.
+
 config XEN_SCRUB_PAGES
        bool "Scrub pages before returning them to system"
        depends on XEN_BALLOON
index 0b52d92cb2e52d03899dd410d8a58e7640c8d8d5..fd933695f2328f29c2493ee751f22230ec68cbb1 100644 (file)
@@ -229,6 +229,29 @@ static enum bp_state reserve_additional_memory(long credit)
        balloon_hotplug = round_up(balloon_hotplug, PAGES_PER_SECTION);
        nid = memory_add_physaddr_to_nid(hotplug_start_paddr);
 
+#ifdef CONFIG_XEN_HAVE_PVMMU
+        /*
+         * add_memory() will build page tables for the new memory so
+         * the p2m must contain invalid entries so the correct
+         * non-present PTEs will be written.
+         *
+         * If a failure occurs, the original (identity) p2m entries
+         * are not restored since this region is now known not to
+         * conflict with any devices.
+         */ 
+       if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+               unsigned long pfn, i;
+
+               pfn = PFN_DOWN(hotplug_start_paddr);
+               for (i = 0; i < balloon_hotplug; i++) {
+                       if (!set_phys_to_machine(pfn + i, INVALID_P2M_ENTRY)) {
+                               pr_warn("set_phys_to_machine() failed, no memory added\n");
+                               return BP_ECANCELED;
+                       }
+                }
+       }
+#endif
+
        rc = add_memory(nid, hotplug_start_paddr, balloon_hotplug << PAGE_SHIFT);
 
        if (rc) {
index 4ac7445e6ec70516848e942f54a6846a8541113b..aa0dc2573374184597b9e449fad6467f924f0f45 100644 (file)
@@ -1,6 +1,9 @@
 /*
  *   fs/cifs/cifsencrypt.c
  *
+ *   Encryption and hashing operations relating to NTLM, NTLMv2.  See MS-NLMP
+ *   for more detailed information
+ *
  *   Copyright (C) International Business Machines  Corp., 2005,2013
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
@@ -515,7 +518,8 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
                                 __func__);
                        return rc;
                }
-       } else if (ses->serverName) {
+       } else {
+               /* We use ses->serverName if no domain name available */
                len = strlen(ses->serverName);
 
                server = kmalloc(2 + (len * 2), GFP_KERNEL);
index d3aa999ab78520fcd4819f99548247e231df591b..480cf9c81d505b8351dd76eee0f012110c3f2b9c 100644 (file)
@@ -1599,6 +1599,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                                pr_warn("CIFS: username too long\n");
                                goto cifs_parse_mount_err;
                        }
+
+                       kfree(vol->username);
                        vol->username = kstrdup(string, GFP_KERNEL);
                        if (!vol->username)
                                goto cifs_parse_mount_err;
@@ -1700,6 +1702,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                                goto cifs_parse_mount_err;
                        }
 
+                       kfree(vol->domainname);
                        vol->domainname = kstrdup(string, GFP_KERNEL);
                        if (!vol->domainname) {
                                pr_warn("CIFS: no memory for domainname\n");
@@ -1731,6 +1734,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        }
 
                         if (strncasecmp(string, "default", 7) != 0) {
+                               kfree(vol->iocharset);
                                vol->iocharset = kstrdup(string,
                                                         GFP_KERNEL);
                                if (!vol->iocharset) {
@@ -2913,8 +2917,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
                 * calling name ends in null (byte 16) from old smb
                 * convention.
                 */
-               if (server->workstation_RFC1001_name &&
-                   server->workstation_RFC1001_name[0] != 0)
+               if (server->workstation_RFC1001_name[0] != 0)
                        rfc1002mangle(ses_init_buf->trailer.
                                      session_req.calling_name,
                                      server->workstation_RFC1001_name,
@@ -3692,6 +3695,12 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
 #endif /* CIFS_WEAK_PW_HASH */
                rc = SMBNTencrypt(tcon->password, ses->server->cryptkey,
                                        bcc_ptr, nls_codepage);
+               if (rc) {
+                       cifs_dbg(FYI, "%s Can't generate NTLM rsp. Error: %d\n",
+                                __func__, rc);
+                       cifs_buf_release(smb_buffer);
+                       return rc;
+               }
 
                bcc_ptr += CIFS_AUTH_RESP_SIZE;
                if (ses->capabilities & CAP_UNICODE) {
index a94b3e67318283dd54d61fc595ecb2037ba3a515..ca30c391a894a0e9df8eac6ed1ede194c89f1885 100644 (file)
@@ -1823,6 +1823,7 @@ refind_writable:
                        cifsFileInfo_put(inv_file);
                        spin_lock(&cifs_file_list_lock);
                        ++refind;
+                       inv_file = NULL;
                        goto refind_writable;
                }
        }
index 2d4f37235ed0fa360782ae237c89fccccbf8b719..3e126d7bb2ea5bec97c9d6e02973a49886261580 100644 (file)
@@ -771,6 +771,8 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
                                cifs_buf_release(srchinf->ntwrk_buf_start);
                        }
                        kfree(srchinf);
+                       if (rc)
+                               goto cgii_exit;
        } else
                goto cgii_exit;
 
index 689f035915cf70f075d71fca5e281ec009c5420a..22dfdf17d06547f3d1b3abbc302bb03abf1b047b 100644 (file)
@@ -322,7 +322,7 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
 
        /* return pointer to beginning of data area, ie offset from SMB start */
        if ((*off != 0) && (*len != 0))
-               return hdr->ProtocolId + *off;
+               return (char *)(&hdr->ProtocolId[0]) + *off;
        else
                return NULL;
 }
index 96b5d40a2ece611b27ed19668cc4b7b665605113..eab05e1aa587424863d6914eb351da9fdcf17437 100644 (file)
@@ -684,7 +684,8 @@ smb2_clone_range(const unsigned int xid,
 
                        /* No need to change MaxChunks since already set to 1 */
                        chunk_sizes_updated = true;
-               }
+               } else
+                       goto cchunk_out;
        }
 
 cchunk_out:
index 3417340bf89e677fe0c46bf98cf922dd39d29a3a..65cd7a84c8bc3206033a917fe9d98fc939cbe1af 100644 (file)
@@ -1218,7 +1218,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        struct smb2_ioctl_req *req;
        struct smb2_ioctl_rsp *rsp;
        struct TCP_Server_Info *server;
-       struct cifs_ses *ses = tcon->ses;
+       struct cifs_ses *ses;
        struct kvec iov[2];
        int resp_buftype;
        int num_iovecs;
@@ -1233,6 +1233,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        if (plen)
                *plen = 0;
 
+       if (tcon)
+               ses = tcon->ses;
+       else
+               return -EIO;
+
        if (ses && (ses->server))
                server = ses->server;
        else
@@ -1296,14 +1301,12 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        rsp = (struct smb2_ioctl_rsp *)iov[0].iov_base;
 
        if ((rc != 0) && (rc != -EINVAL)) {
-               if (tcon)
-                       cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
+               cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
                goto ioctl_exit;
        } else if (rc == -EINVAL) {
                if ((opcode != FSCTL_SRV_COPYCHUNK_WRITE) &&
                    (opcode != FSCTL_SRV_COPYCHUNK)) {
-                       if (tcon)
-                               cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
+                       cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
                        goto ioctl_exit;
                }
        }
@@ -1629,7 +1632,7 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
 
        rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0);
 
-       if ((rc != 0) && tcon)
+       if (rc != 0)
                cifs_stats_fail_inc(tcon, SMB2_FLUSH_HE);
 
        free_rsp_buf(resp_buftype, iov[0].iov_base);
@@ -2114,7 +2117,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
        struct kvec iov[2];
        int rc = 0;
        int len;
-       int resp_buftype;
+       int resp_buftype = CIFS_NO_BUFFER;
        unsigned char *bufptr;
        struct TCP_Server_Info *server;
        struct cifs_ses *ses = tcon->ses;
index e907052eeadb69f683df3c7d8838106c6e36905b..32a8bbd7a9ad1121f9b100da08f80500736bcebf 100644 (file)
@@ -53,6 +53,18 @@ struct wb_writeback_work {
        struct completion *done;        /* set if the caller waits */
 };
 
+/*
+ * If an inode is constantly having its pages dirtied, but then the
+ * updates stop dirtytime_expire_interval seconds in the past, it's
+ * possible for the worst case time between when an inode has its
+ * timestamps updated and when they finally get written out to be two
+ * dirtytime_expire_intervals.  We set the default to 12 hours (in
+ * seconds), which means most of the time inodes will have their
+ * timestamps written to disk after 12 hours, but in the worst case a
+ * few inodes might not their timestamps updated for 24 hours.
+ */
+unsigned int dirtytime_expire_interval = 12 * 60 * 60;
+
 /**
  * writeback_in_progress - determine whether there is writeback in progress
  * @bdi: the device's backing_dev_info structure.
@@ -275,8 +287,8 @@ static int move_expired_inodes(struct list_head *delaying_queue,
 
        if ((flags & EXPIRE_DIRTY_ATIME) == 0)
                older_than_this = work->older_than_this;
-       else if ((work->reason == WB_REASON_SYNC) == 0) {
-               expire_time = jiffies - (HZ * 86400);
+       else if (!work->for_sync) {
+               expire_time = jiffies - (dirtytime_expire_interval * HZ);
                older_than_this = &expire_time;
        }
        while (!list_empty(delaying_queue)) {
@@ -458,6 +470,7 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb,
                 */
                redirty_tail(inode, wb);
        } else if (inode->i_state & I_DIRTY_TIME) {
+               inode->dirtied_when = jiffies;
                list_move(&inode->i_wb_list, &wb->b_dirty_time);
        } else {
                /* The inode is clean. Remove from writeback lists. */
@@ -505,12 +518,17 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
        spin_lock(&inode->i_lock);
 
        dirty = inode->i_state & I_DIRTY;
-       if (((dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) &&
-            (inode->i_state & I_DIRTY_TIME)) ||
-           (inode->i_state & I_DIRTY_TIME_EXPIRED)) {
-               dirty |= I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED;
-               trace_writeback_lazytime(inode);
-       }
+       if (inode->i_state & I_DIRTY_TIME) {
+               if ((dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) ||
+                   unlikely(inode->i_state & I_DIRTY_TIME_EXPIRED) ||
+                   unlikely(time_after(jiffies,
+                                       (inode->dirtied_time_when +
+                                        dirtytime_expire_interval * HZ)))) {
+                       dirty |= I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED;
+                       trace_writeback_lazytime(inode);
+               }
+       } else
+               inode->i_state &= ~I_DIRTY_TIME_EXPIRED;
        inode->i_state &= ~dirty;
 
        /*
@@ -1131,6 +1149,56 @@ void wakeup_flusher_threads(long nr_pages, enum wb_reason reason)
        rcu_read_unlock();
 }
 
+/*
+ * Wake up bdi's periodically to make sure dirtytime inodes gets
+ * written back periodically.  We deliberately do *not* check the
+ * b_dirtytime list in wb_has_dirty_io(), since this would cause the
+ * kernel to be constantly waking up once there are any dirtytime
+ * inodes on the system.  So instead we define a separate delayed work
+ * function which gets called much more rarely.  (By default, only
+ * once every 12 hours.)
+ *
+ * If there is any other write activity going on in the file system,
+ * this function won't be necessary.  But if the only thing that has
+ * happened on the file system is a dirtytime inode caused by an atime
+ * update, we need this infrastructure below to make sure that inode
+ * eventually gets pushed out to disk.
+ */
+static void wakeup_dirtytime_writeback(struct work_struct *w);
+static DECLARE_DELAYED_WORK(dirtytime_work, wakeup_dirtytime_writeback);
+
+static void wakeup_dirtytime_writeback(struct work_struct *w)
+{
+       struct backing_dev_info *bdi;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) {
+               if (list_empty(&bdi->wb.b_dirty_time))
+                       continue;
+               bdi_wakeup_thread(bdi);
+       }
+       rcu_read_unlock();
+       schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ);
+}
+
+static int __init start_dirtytime_writeback(void)
+{
+       schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ);
+       return 0;
+}
+__initcall(start_dirtytime_writeback);
+
+int dirtytime_interval_handler(struct ctl_table *table, int write,
+                              void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       int ret;
+
+       ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+       if (ret == 0 && write)
+               mod_delayed_work(system_wq, &dirtytime_work, 0);
+       return ret;
+}
+
 static noinline void block_dump___mark_inode_dirty(struct inode *inode)
 {
        if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) {
@@ -1269,8 +1337,13 @@ void __mark_inode_dirty(struct inode *inode, int flags)
                        }
 
                        inode->dirtied_when = jiffies;
-                       list_move(&inode->i_wb_list, dirtytime ?
-                                 &bdi->wb.b_dirty_time : &bdi->wb.b_dirty);
+                       if (dirtytime)
+                               inode->dirtied_time_when = jiffies;
+                       if (inode->i_state & (I_DIRTY_INODE | I_DIRTY_PAGES))
+                               list_move(&inode->i_wb_list, &bdi->wb.b_dirty);
+                       else
+                               list_move(&inode->i_wb_list,
+                                         &bdi->wb.b_dirty_time);
                        spin_unlock(&bdi->wb.list_lock);
                        trace_writeback_dirty_inode_enqueue(inode);
 
index 528fedfda15e6432bd69b80c7bd8faceb7d1351d..40bc384728c0e07b637dccfa755fe49b5751bf86 100644 (file)
@@ -1388,9 +1388,8 @@ any_leases_conflict(struct inode *inode, struct file_lock *breaker)
 int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
 {
        int error = 0;
-       struct file_lock *new_fl;
        struct file_lock_context *ctx = inode->i_flctx;
-       struct file_lock *fl;
+       struct file_lock *new_fl, *fl, *tmp;
        unsigned long break_time;
        int want_write = (mode & O_ACCMODE) != O_RDONLY;
        LIST_HEAD(dispose);
@@ -1420,7 +1419,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
                        break_time++;   /* so that 0 means no break time */
        }
 
-       list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
+       list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) {
                if (!leases_conflict(fl, new_fl))
                        continue;
                if (want_write) {
index cdbc78c7254218c80213877e90c08ec107aea223..03d647bf195d78bb3d6611553c9ad3e6fa4385a2 100644 (file)
@@ -137,7 +137,7 @@ nfsd4_block_proc_layoutget(struct inode *inode, const struct svc_fh *fhp,
        seg->offset = iomap.offset;
        seg->length = iomap.length;
 
-       dprintk("GET: %lld:%lld %d\n", bex->foff, bex->len, bex->es);
+       dprintk("GET: 0x%llx:0x%llx %d\n", bex->foff, bex->len, bex->es);
        return 0;
 
 out_error:
index 9da89fddab338fcebbeb51fc0ec71534e0defc5a..9aa2796da90d9169488a625d5f80e90010971ff4 100644 (file)
@@ -122,19 +122,19 @@ nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
 
                p = xdr_decode_hyper(p, &bex.foff);
                if (bex.foff & (block_size - 1)) {
-                       dprintk("%s: unaligned offset %lld\n",
+                       dprintk("%s: unaligned offset 0x%llx\n",
                                __func__, bex.foff);
                        goto fail;
                }
                p = xdr_decode_hyper(p, &bex.len);
                if (bex.len & (block_size - 1)) {
-                       dprintk("%s: unaligned length %lld\n",
+                       dprintk("%s: unaligned length 0x%llx\n",
                                __func__, bex.foff);
                        goto fail;
                }
                p = xdr_decode_hyper(p, &bex.soff);
                if (bex.soff & (block_size - 1)) {
-                       dprintk("%s: unaligned disk offset %lld\n",
+                       dprintk("%s: unaligned disk offset 0x%llx\n",
                                __func__, bex.soff);
                        goto fail;
                }
index 1028a062954357c06005dc7b0d6f61a10ea6f418..6904213a436368e47628af85701a3beb68e0550b 100644 (file)
@@ -118,7 +118,7 @@ void nfsd4_setup_layout_type(struct svc_export *exp)
 {
        struct super_block *sb = exp->ex_path.mnt->mnt_sb;
 
-       if (exp->ex_flags & NFSEXP_NOPNFS)
+       if (!(exp->ex_flags & NFSEXP_PNFS))
                return;
 
        if (sb->s_export_op->get_uuid &&
@@ -440,15 +440,14 @@ nfsd4_return_file_layout(struct nfs4_layout *lp, struct nfsd4_layout_seg *seg,
                        list_move_tail(&lp->lo_perstate, reaplist);
                        return;
                }
-               end = seg->offset;
+               lo->offset = layout_end(seg);
        } else {
                /* retain the whole layout segment on a split. */
                if (layout_end(seg) < end) {
                        dprintk("%s: split not supported\n", __func__);
                        return;
                }
-
-               lo->offset = layout_end(seg);
+               end = seg->offset;
        }
 
        layout_update_len(lo, end);
@@ -513,6 +512,9 @@ nfsd4_return_client_layouts(struct svc_rqst *rqstp,
 
        spin_lock(&clp->cl_lock);
        list_for_each_entry_safe(ls, n, &clp->cl_lo_states, ls_perclnt) {
+               if (ls->ls_layout_type != lrp->lr_layout_type)
+                       continue;
+
                if (lrp->lr_return_type == RETURN_FSID &&
                    !fh_fsid_match(&ls->ls_stid.sc_file->fi_fhandle,
                                   &cstate->current_fh.fh_handle))
@@ -587,6 +589,8 @@ nfsd4_cb_layout_fail(struct nfs4_layout_stateid *ls)
 
        rpc_ntop((struct sockaddr *)&clp->cl_addr, addr_str, sizeof(addr_str));
 
+       trace_layout_recall_fail(&ls->ls_stid.sc_stateid);
+
        printk(KERN_WARNING
                "nfsd: client %s failed to respond to layout recall. "
                "  Fencing..\n", addr_str);
index d30bea8d0277ab3bfa45e7d66c38ed410026f585..92b9d97aff4f1adfe24ed607d11661196a500ffc 100644 (file)
@@ -1237,8 +1237,8 @@ nfsd4_getdeviceinfo(struct svc_rqst *rqstp,
                nfserr = ops->proc_getdeviceinfo(exp->ex_path.mnt->mnt_sb, gdp);
 
        gdp->gd_notify_types &= ops->notify_types;
-       exp_put(exp);
 out:
+       exp_put(exp);
        return nfserr;
 }
 
index d2f2c37dc2dbd2649399fe2ddad4032a5025d337..8ba1d888f1e624d672453bd1eea20c40e054f746 100644 (file)
@@ -3221,7 +3221,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
        } else
                nfs4_free_openowner(&oo->oo_owner);
        spin_unlock(&clp->cl_lock);
-       return oo;
+       return ret;
 }
 
 static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
@@ -5062,7 +5062,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp,
        } else
                nfs4_free_lockowner(&lo->lo_owner);
        spin_unlock(&clp->cl_lock);
-       return lo;
+       return ret;
 }
 
 static void
index df5e66caf100ca303005018932ccc8edadab4089..5fb7e78169a6b27a1a5a4d5e9ec354c9e32f6c43 100644 (file)
@@ -1562,7 +1562,11 @@ nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp,
        p = xdr_decode_hyper(p, &lgp->lg_seg.offset);
        p = xdr_decode_hyper(p, &lgp->lg_seg.length);
        p = xdr_decode_hyper(p, &lgp->lg_minlength);
-       nfsd4_decode_stateid(argp, &lgp->lg_sid);
+
+       status = nfsd4_decode_stateid(argp, &lgp->lg_sid);
+       if (status)
+               return status;
+
        READ_BUF(4);
        lgp->lg_maxcount = be32_to_cpup(p++);
 
@@ -1580,7 +1584,11 @@ nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp,
        p = xdr_decode_hyper(p, &lcp->lc_seg.offset);
        p = xdr_decode_hyper(p, &lcp->lc_seg.length);
        lcp->lc_reclaim = be32_to_cpup(p++);
-       nfsd4_decode_stateid(argp, &lcp->lc_sid);
+
+       status = nfsd4_decode_stateid(argp, &lcp->lc_sid);
+       if (status)
+               return status;
+
        READ_BUF(4);
        lcp->lc_newoffset = be32_to_cpup(p++);
        if (lcp->lc_newoffset) {
@@ -1628,7 +1636,11 @@ nfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp,
                READ_BUF(16);
                p = xdr_decode_hyper(p, &lrp->lr_seg.offset);
                p = xdr_decode_hyper(p, &lrp->lr_seg.length);
-               nfsd4_decode_stateid(argp, &lrp->lr_sid);
+
+               status = nfsd4_decode_stateid(argp, &lrp->lr_sid);
+               if (status)
+                       return status;
+
                READ_BUF(4);
                lrp->lrf_body_len = be32_to_cpup(p++);
                if (lrp->lrf_body_len > 0) {
@@ -4123,7 +4135,7 @@ nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr,
                return nfserr_resource;
        *p++ = cpu_to_be32(lrp->lrs_present);
        if (lrp->lrs_present)
-               nfsd4_encode_stateid(xdr, &lrp->lr_sid);
+               return nfsd4_encode_stateid(xdr, &lrp->lr_sid);
        return nfs_ok;
 }
 #endif /* CONFIG_NFSD_PNFS */
index 83a9694ec485b0593e3de847464243640fcd7186..46ec934f5dee8c529020558bed4cd820956734f1 100644 (file)
@@ -165,13 +165,17 @@ int nfsd_reply_cache_init(void)
 {
        unsigned int hashsize;
        unsigned int i;
+       int status = 0;
 
        max_drc_entries = nfsd_cache_size_limit();
        atomic_set(&num_drc_entries, 0);
        hashsize = nfsd_hashsize(max_drc_entries);
        maskbits = ilog2(hashsize);
 
-       register_shrinker(&nfsd_reply_cache_shrinker);
+       status = register_shrinker(&nfsd_reply_cache_shrinker);
+       if (status)
+               return status;
+
        drc_slab = kmem_cache_create("nfsd_drc", sizeof(struct svc_cacherep),
                                        0, 0, NULL);
        if (!drc_slab)
index 5a4f4900516920278ee89834ea76efc2a7c5c20d..de13bfc3563470b8569278bbd426793d65a31ac4 100644 (file)
@@ -38,17 +38,18 @@ struct dw_hdmi_curr_ctrl {
        u16 curr[DW_HDMI_RES_MAX];
 };
 
-struct dw_hdmi_sym_term {
+struct dw_hdmi_phy_config {
        unsigned long mpixelclock;
        u16 sym_ctr;    /*clock symbol and transmitter control*/
        u16 term;       /*transmission termination value*/
+       u16 vlev_ctr;   /* voltage level control */
 };
 
 struct dw_hdmi_plat_data {
        enum dw_hdmi_devtype dev_type;
        const struct dw_hdmi_mpll_config *mpll_cfg;
        const struct dw_hdmi_curr_ctrl *cur_ctr;
-       const struct dw_hdmi_sym_term *sym_term;
+       const struct dw_hdmi_phy_config *phy_config;
        enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
                                           struct drm_display_mode *mode);
 };
index 63c0b0131f618ead78d21cb7d309113432fe9140..62c40777c009798319a49235af42d040ffc654d6 100644 (file)
@@ -253,7 +253,6 @@ struct drm_ioctl_desc {
        unsigned int cmd;
        int flags;
        drm_ioctl_t *func;
-       unsigned int cmd_drv;
        const char *name;
 };
 
@@ -262,8 +261,13 @@ struct drm_ioctl_desc {
  * ioctl, for use by drm_ioctl().
  */
 
-#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags)                        \
-       [DRM_IOCTL_NR(DRM_##ioctl)] = {.cmd = DRM_##ioctl, .func = _func, .flags = _flags, .cmd_drv = DRM_IOCTL_##ioctl, .name = #ioctl}
+#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags)                                \
+       [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {        \
+               .cmd = DRM_IOCTL_##ioctl,                               \
+               .func = _func,                                          \
+               .flags = _flags,                                        \
+               .name = #ioctl                                          \
+        }
 
 /* Event queued up for userspace to read */
 struct drm_pending_event {
index 51168a8b723a2d45f4ff658eb27d2b54bd5f1d88..c157103492b0d1f02b198685586202e11977bccd 100644 (file)
@@ -75,4 +75,28 @@ int __must_check drm_atomic_check_only(struct drm_atomic_state *state);
 int __must_check drm_atomic_commit(struct drm_atomic_state *state);
 int __must_check drm_atomic_async_commit(struct drm_atomic_state *state);
 
+#define for_each_connector_in_state(state, connector, connector_state, __i) \
+       for ((__i) = 0;                                                 \
+            (connector) = (state)->connectors[__i],                    \
+            (connector_state) = (state)->connector_states[__i],        \
+            (__i) < (state)->num_connector;                            \
+            (__i)++)                                                   \
+               if (connector)
+
+#define for_each_crtc_in_state(state, crtc, crtc_state, __i)   \
+       for ((__i) = 0;                                         \
+            (crtc) = (state)->crtcs[__i],                      \
+            (crtc_state) = (state)->crtc_states[__i],          \
+            (__i) < (state)->dev->mode_config.num_crtc;        \
+            (__i)++)                                           \
+               if (crtc_state)
+
+#define for_each_plane_in_state(state, plane, plane_state, __i)        \
+       for ((__i) = 0;                                         \
+            (plane) = (state)->planes[__i],                    \
+            (plane_state) = (state)->plane_states[__i],        \
+            (__i) < (state)->dev->mode_config.num_total_plane; \
+            (__i)++)                                           \
+               if (plane_state)
+
 #endif /* DRM_ATOMIC_H_ */
index 829280b56874a4057f8c509739bb04f6466d4272..d665781eb54293deb008d89d7a5a43c575243d60 100644 (file)
@@ -87,20 +87,34 @@ void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
 
 /* default implementations for state handling */
 void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
+void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
+                                             struct drm_crtc_state *state);
 struct drm_crtc_state *
 drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc);
+void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
+                                           struct drm_crtc_state *state);
 void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
                                          struct drm_crtc_state *state);
 
 void drm_atomic_helper_plane_reset(struct drm_plane *plane);
+void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
+                                              struct drm_plane_state *state);
 struct drm_plane_state *
 drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane);
+void __drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
+                                            struct drm_plane_state *state);
 void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
                                          struct drm_plane_state *state);
 
 void drm_atomic_helper_connector_reset(struct drm_connector *connector);
+void
+__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
+                                          struct drm_connector_state *state);
 struct drm_connector_state *
 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);
 void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
                                          struct drm_connector_state *state);
 
index adc9ea5acf02ea45437268c16298a4dbbd9fe35a..ca71c03143d1bc07a161267b35d2de80a2a4b279 100644 (file)
@@ -53,7 +53,6 @@ struct fence;
 #define DRM_MODE_OBJECT_FB 0xfbfbfbfb
 #define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb
 #define DRM_MODE_OBJECT_PLANE 0xeeeeeeee
-#define DRM_MODE_OBJECT_BRIDGE 0xbdbdbdbd
 #define DRM_MODE_OBJECT_ANY 0
 
 struct drm_mode_object {
@@ -467,7 +466,7 @@ struct drm_crtc {
        int framedur_ns, linedur_ns, pixeldur_ns;
 
        /* if you are using the helper */
-       void *helper_private;
+       const void *helper_private;
 
        struct drm_object_properties properties;
 
@@ -597,7 +596,7 @@ struct drm_encoder {
        struct drm_crtc *crtc;
        struct drm_bridge *bridge;
        const struct drm_encoder_funcs *funcs;
-       void *helper_private;
+       const void *helper_private;
 };
 
 /* should we poll this connector for connects and disconnects */
@@ -701,7 +700,7 @@ struct drm_connector {
        /* requested DPMS state */
        int dpms;
 
-       void *helper_private;
+       const void *helper_private;
 
        /* forced on connector */
        struct drm_cmdline_mode cmdline_mode;
@@ -864,7 +863,7 @@ struct drm_plane {
 
        enum drm_plane_type type;
 
-       void *helper_private;
+       const void *helper_private;
 
        struct drm_plane_state *state;
 };
@@ -915,7 +914,7 @@ struct drm_bridge {
 };
 
 /**
- * struct struct drm_atomic_state - the global state object for atomic updates
+ * struct drm_atomic_state - the global state object for atomic updates
  * @dev: parent DRM device
  * @allow_modeset: allow full modeset
  * @legacy_cursor_update: hint to enforce legacy cursor ioctl semantics
@@ -975,7 +974,7 @@ struct drm_mode_set {
  * struct drm_mode_config_funcs - basic driver provided mode setting functions
  * @fb_create: create a new framebuffer object
  * @output_poll_changed: function to handle output configuration changes
- * @atomic_check: check whether a give atomic state update is possible
+ * @atomic_check: check whether a given atomic state update is possible
  * @atomic_commit: commit an atomic state update previously verified with
  *     atomic_check()
  *
index 92d5135b55d214e54cdff5bf83a33ceea7e83e2f..c8fc187061de5fbd9fc8545f602a62baaa45b8cc 100644 (file)
@@ -197,19 +197,19 @@ extern void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
 static inline void drm_crtc_helper_add(struct drm_crtc *crtc,
                                       const struct drm_crtc_helper_funcs *funcs)
 {
-       crtc->helper_private = (void *)funcs;
+       crtc->helper_private = funcs;
 }
 
 static inline void drm_encoder_helper_add(struct drm_encoder *encoder,
                                          const struct drm_encoder_helper_funcs *funcs)
 {
-       encoder->helper_private = (void *)funcs;
+       encoder->helper_private = funcs;
 }
 
 static inline void drm_connector_helper_add(struct drm_connector *connector,
                                            const struct drm_connector_helper_funcs *funcs)
 {
-       connector->helper_private = (void *)funcs;
+       connector->helper_private = funcs;
 }
 
 extern void drm_helper_resume_force_mode(struct drm_device *dev);
index c5fdc2d3ca97275c36d86954d52b29b7e60c7f7b..523f04c90dea45826af4a3de70a43d54896f6043 100644 (file)
@@ -42,6 +42,8 @@
  * 1.2 formally includes both eDP and DPI definitions.
  */
 
+#define DP_AUX_MAX_PAYLOAD_BYTES       16
+
 #define DP_AUX_I2C_WRITE               0x0
 #define DP_AUX_I2C_READ                        0x1
 #define DP_AUX_I2C_STATUS              0x2
@@ -680,6 +682,9 @@ struct drm_dp_aux_msg {
  * transactions. The drm_dp_aux_register_i2c_bus() function registers an
  * I2C adapter that can be passed to drm_probe_ddc(). Upon removal, drivers
  * should call drm_dp_aux_unregister_i2c_bus() to remove the I2C adapter.
+ * The I2C adapter uses long transfers by default; if a partial response is
+ * received, the adapter will drop down to the size given by the partial
+ * response for this transaction only.
  *
  * Note that the aux helper code assumes that the .transfer() function
  * only modifies the reply field of the drm_dp_aux_msg structure.  The
index 00c1da9272456e8e9bdec207affa286028664421..a2507817be4196606abe1cc038be09c612d6afd6 100644 (file)
@@ -486,6 +486,8 @@ int drm_dp_calc_pbn_mode(int clock, int bpp);
 
 bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int pbn, int *slots);
 
+int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
+
 
 void drm_dp_mst_reset_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
 
index 87d85e81d3a7e076a36e35eb65b94ca7ecbc8751..799050198323e852c7cbb45e3c1236cc67d386ac 100644 (file)
@@ -215,6 +215,8 @@ struct detailed_timing {
 #define DRM_ELD_VER                    0
 # define DRM_ELD_VER_SHIFT             3
 # define DRM_ELD_VER_MASK              (0x1f << 3)
+# define DRM_ELD_VER_CEA861D           (2 << 3) /* supports 861D or below */
+# define DRM_ELD_VER_CANNED            (0x1f << 3)
 
 #define DRM_ELD_BASELINE_ELD_LEN       2       /* in dwords! */
 
index 21b944c456f69dceb9c4762384d04717d82b41ff..0dfd94def593526eaa7d5e414a85634f37509385 100644 (file)
@@ -44,6 +44,25 @@ struct drm_fb_helper_crtc {
        int x, y;
 };
 
+/**
+ * struct drm_fb_helper_surface_size - describes fbdev size and scanout surface size
+ * @fb_width: fbdev width
+ * @fb_height: fbdev height
+ * @surface_width: scanout buffer width
+ * @surface_height: scanout buffer height
+ * @surface_bpp: scanout buffer bpp
+ * @surface_depth: scanout buffer depth
+ *
+ * Note that the scanout surface width/height may be larger than the fbdev
+ * width/height.  In case of multiple displays, the scanout surface is sized
+ * according to the largest width/height (so it is large enough for all CRTCs
+ * to scanout).  But the fbdev width/height is sized to the minimum width/
+ * height of all the displays.  This ensures that fbcon fits on the smallest
+ * of the attached displays.
+ *
+ * So what is passed to drm_fb_helper_fill_var() should be fb_width/fb_height,
+ * rather than the surface size.
+ */
 struct drm_fb_helper_surface_size {
        u32 fb_width;
        u32 fb_height;
index 1e6ae1458f7ab98ef42cd66ef9834cef8f276718..7a592d7e398b0e4c1c1eca5dd50bff816a634972 100644 (file)
@@ -149,14 +149,16 @@ drm_gem_object_unreference(struct drm_gem_object *obj)
 static inline void
 drm_gem_object_unreference_unlocked(struct drm_gem_object *obj)
 {
-       if (obj && !atomic_add_unless(&obj->refcount.refcount, -1, 1)) {
-               struct drm_device *dev = obj->dev;
+       struct drm_device *dev;
+
+       if (!obj)
+               return;
 
-               mutex_lock(&dev->struct_mutex);
-               if (likely(atomic_dec_and_test(&obj->refcount.refcount)))
-                       drm_gem_object_free(&obj->refcount);
+       dev = obj->dev;
+       if (kref_put_mutex(&obj->refcount, drm_gem_object_free, &dev->struct_mutex))
                mutex_unlock(&dev->struct_mutex);
-       }
+       else
+               might_lock(&dev->struct_mutex);
 }
 
 int drm_gem_handle_create(struct drm_file *file_priv,
index 1fbcc96063a7ff7ed72f3be91a3cb47f0d6142dd..13ff44b28893f5904aa43cfd2b3fbc4d417f24bc 100644 (file)
@@ -29,6 +29,7 @@
 struct drm_connector;
 struct drm_device;
 struct drm_panel;
+struct display_timing;
 
 /**
  * struct drm_panel_funcs - perform operations on a given panel
@@ -38,6 +39,8 @@ struct drm_panel;
  * @enable: enable panel (turn on back light, etc.)
  * @get_modes: add modes to the connector that the panel is attached to and
  * return the number of modes added
+ * @get_timings: copy display timings into the provided array and return
+ * the number of display timings available
  *
  * The .prepare() function is typically called before the display controller
  * starts to transmit video data. Panel drivers can use this to turn the panel
@@ -68,6 +71,8 @@ struct drm_panel_funcs {
        int (*prepare)(struct drm_panel *panel);
        int (*enable)(struct drm_panel *panel);
        int (*get_modes)(struct drm_panel *panel);
+       int (*get_timings)(struct drm_panel *panel, unsigned int num_timings,
+                          struct display_timing *timings);
 };
 
 struct drm_panel {
index e48157a5a59ccad82ab8498a4876c7fe208c3dfc..96e16283afb96ca3227a96733e6e6ff57acaac2a 100644 (file)
@@ -76,7 +76,7 @@ struct drm_plane_helper_funcs {
 static inline void drm_plane_helper_add(struct drm_plane *plane,
                                        const struct drm_plane_helper_funcs *funcs)
 {
-       plane->helper_private = (void *)funcs;
+       plane->helper_private = funcs;
 }
 
 extern int drm_plane_helper_check_update(struct drm_plane *plane,
index b4d71b5e1ff23a2d3f3ec5c481937edd571ead4d..f4131e8ead74965a73272949b3a9eae8fa08b5c7 100644 (file)
@@ -604,6 +604,7 @@ struct inode {
        struct mutex            i_mutex;
 
        unsigned long           dirtied_when;   /* jiffies of first dirtying */
+       unsigned long           dirtied_time_when;
 
        struct hlist_node       i_hash;
        struct list_head        i_wb_list;      /* backing dev IO list */
index 464f33814a94d0ccf82f20b69041188fedb96b59..d2ba7d334039ec2f7660eaabfb94fd4446a65018 100644 (file)
@@ -135,6 +135,7 @@ struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id);
 u32 host1x_syncpt_id(struct host1x_syncpt *sp);
 u32 host1x_syncpt_read_min(struct host1x_syncpt *sp);
 u32 host1x_syncpt_read_max(struct host1x_syncpt *sp);
+u32 host1x_syncpt_read(struct host1x_syncpt *sp);
 int host1x_syncpt_incr(struct host1x_syncpt *sp);
 u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs);
 int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
index 781974afff9f14e576a7912039a5fb68009cdb25..ffbc034c88104d251c3891f4513c12a62818c5dd 100644 (file)
 #define GICR_PROPBASER_WaWb            (5U << 7)
 #define GICR_PROPBASER_RaWaWt          (6U << 7)
 #define GICR_PROPBASER_RaWaWb          (7U << 7)
+#define GICR_PROPBASER_CACHEABILITY_MASK (7U << 7)
 #define GICR_PROPBASER_IDBITS_MASK     (0x1f)
 
+#define GICR_PENDBASER_NonShareable    (0U << 10)
+#define GICR_PENDBASER_InnerShareable  (1U << 10)
+#define GICR_PENDBASER_OuterShareable  (2U << 10)
+#define GICR_PENDBASER_SHAREABILITY_MASK (3UL << 10)
+#define GICR_PENDBASER_nCnB            (0U << 7)
+#define GICR_PENDBASER_nC              (1U << 7)
+#define GICR_PENDBASER_RaWt            (2U << 7)
+#define GICR_PENDBASER_RaWb            (3U << 7)
+#define GICR_PENDBASER_WaWt            (4U << 7)
+#define GICR_PENDBASER_WaWb            (5U << 7)
+#define GICR_PENDBASER_RaWaWt          (6U << 7)
+#define GICR_PENDBASER_RaWaWb          (7U << 7)
+#define GICR_PENDBASER_CACHEABILITY_MASK (7U << 7)
+
 /*
  * Re-Distributor registers, offsets from SGI_base
  */
 #define GITS_CBASER_WaWb               (5UL << 59)
 #define GITS_CBASER_RaWaWt             (6UL << 59)
 #define GITS_CBASER_RaWaWb             (7UL << 59)
+#define GITS_CBASER_CACHEABILITY_MASK  (7UL << 59)
 #define GITS_CBASER_NonShareable       (0UL << 10)
 #define GITS_CBASER_InnerShareable     (1UL << 10)
 #define GITS_CBASER_OuterShareable     (2UL << 10)
 #define GITS_BASER_WaWb                        (5UL << 59)
 #define GITS_BASER_RaWaWt              (6UL << 59)
 #define GITS_BASER_RaWaWb              (7UL << 59)
+#define GITS_BASER_CACHEABILITY_MASK   (7UL << 59)
 #define GITS_BASER_TYPE_SHIFT          (56)
 #define GITS_BASER_TYPE(r)             (((r) >> GITS_BASER_TYPE_SHIFT) & 7)
 #define GITS_BASER_ENTRY_SIZE_SHIFT    (48)
index 7bf01d779b4532a5a8d168d0ff91fd08d5228e02..1ce79a7f1daa18868adfe14598c35206382f58a5 100644 (file)
@@ -4,5 +4,6 @@
 #include <linux/compiler.h>
 
 unsigned long lcm(unsigned long a, unsigned long b) __attribute_const__;
+unsigned long lcm_not_zero(unsigned long a, unsigned long b) __attribute_const__;
 
 #endif /* _LCM_H */
index dcf6ec27739b1d8bfb98c82e8902ca0b697df5f8..278738873703c119dfa322c13b2755e2176a61f5 100644 (file)
@@ -2185,6 +2185,12 @@ void netdev_freemem(struct net_device *dev);
 void synchronize_net(void);
 int init_dummy_netdev(struct net_device *dev);
 
+DECLARE_PER_CPU(int, xmit_recursion);
+static inline int dev_recursion_level(void)
+{
+       return this_cpu_read(xmit_recursion);
+}
+
 struct net_device *dev_get_by_index(struct net *net, int ifindex);
 struct net_device *__dev_get_by_index(struct net *net, int ifindex);
 struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex);
index befef42e015bbe8b51e1fd7b3fcf49ae76d90afa..7bc92e0506087d0b97995a9aa74cc56060c12fa8 100644 (file)
@@ -14,6 +14,8 @@
 #ifndef __LINUX_OF_GRAPH_H
 #define __LINUX_OF_GRAPH_H
 
+#include <linux/types.h>
+
 /**
  * struct of_endpoint - the OF graph endpoint data structure
  * @port: identifier (value of reg property) of a port this endpoint belongs to
@@ -26,9 +28,21 @@ struct of_endpoint {
        const struct device_node *local_node;
 };
 
+/**
+ * for_each_endpoint_of_node - iterate over every endpoint in a device node
+ * @parent: parent device node containing ports and endpoints
+ * @child: loop variable pointing to the current endpoint node
+ *
+ * When breaking out of the loop, of_node_put(child) has to be called manually.
+ */
+#define for_each_endpoint_of_node(parent, child) \
+       for (child = of_graph_get_next_endpoint(parent, NULL); child != NULL; \
+            child = of_graph_get_next_endpoint(parent, child))
+
 #ifdef CONFIG_OF
 int of_graph_parse_endpoint(const struct device_node *node,
                                struct of_endpoint *endpoint);
+struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id);
 struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
                                        struct device_node *previous);
 struct device_node *of_graph_get_remote_port_parent(
@@ -42,6 +56,12 @@ static inline int of_graph_parse_endpoint(const struct device_node *node,
        return -ENOSYS;
 }
 
+static inline struct device_node *of_graph_get_port_by_id(
+                                       struct device_node *node, u32 id)
+{
+       return NULL;
+}
+
 static inline struct device_node *of_graph_get_next_endpoint(
                                        const struct device_node *parent,
                                        struct device_node *previous)
index c57d8ea0716cddea1419a37481dbd7704b230d65..59a7889e15db51c3b24bc771dbe5d0b1c965212d 100644 (file)
@@ -60,17 +60,17 @@ struct rpc_xprt;
 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
 void           rpc_register_sysctl(void);
 void           rpc_unregister_sysctl(void);
-int            sunrpc_debugfs_init(void);
+void           sunrpc_debugfs_init(void);
 void           sunrpc_debugfs_exit(void);
-int            rpc_clnt_debugfs_register(struct rpc_clnt *);
+void           rpc_clnt_debugfs_register(struct rpc_clnt *);
 void           rpc_clnt_debugfs_unregister(struct rpc_clnt *);
-int            rpc_xprt_debugfs_register(struct rpc_xprt *);
+void           rpc_xprt_debugfs_register(struct rpc_xprt *);
 void           rpc_xprt_debugfs_unregister(struct rpc_xprt *);
 #else
-static inline int
+static inline void
 sunrpc_debugfs_init(void)
 {
-       return 0;
+       return;
 }
 
 static inline void
@@ -79,10 +79,10 @@ sunrpc_debugfs_exit(void)
        return;
 }
 
-static inline int
+static inline void
 rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
 {
-       return 0;
+       return;
 }
 
 static inline void
@@ -91,10 +91,10 @@ rpc_clnt_debugfs_unregister(struct rpc_clnt *clnt)
        return;
 }
 
-static inline int
+static inline void
 rpc_xprt_debugfs_register(struct rpc_xprt *xprt)
 {
-       return 0;
+       return;
 }
 
 static inline void
index d9a4905e01d0c98b88e89c7db5c85bbf7d5be8a1..6e0ce8c7b8cb5a9fcb985a5a5078f82267d03092 100644 (file)
@@ -227,9 +227,23 @@ struct skb_data {  /* skb->cb is one of these */
        struct urb              *urb;
        struct usbnet           *dev;
        enum skb_state          state;
-       size_t                  length;
+       long                    length;
+       unsigned long           packets;
 };
 
+/* Drivers that set FLAG_MULTI_PACKET must call this in their
+ * tx_fixup method before returning an skb.
+ */
+static inline void
+usbnet_set_skb_tx_stats(struct sk_buff *skb,
+                       unsigned long packets, long bytes_delta)
+{
+       struct skb_data *entry = (struct skb_data *) skb->cb;
+
+       entry->packets = packets;
+       entry->length = bytes_delta;
+}
+
 extern int usbnet_open(struct net_device *net);
 extern int usbnet_stop(struct net_device *net);
 extern netdev_tx_t usbnet_start_xmit(struct sk_buff *skb,
index 00048339c23e4f252ee6a4b15cd38b49b8032de4..b2dd371ec0ca0aa6f0e1dc71d1f79c69c6dbdb2b 100644 (file)
@@ -130,6 +130,7 @@ extern int vm_dirty_ratio;
 extern unsigned long vm_dirty_bytes;
 extern unsigned int dirty_writeback_interval;
 extern unsigned int dirty_expire_interval;
+extern unsigned int dirtytime_expire_interval;
 extern int vm_highmem_is_dirtyable;
 extern int block_dump;
 extern int laptop_mode;
@@ -146,6 +147,8 @@ extern int dirty_ratio_handler(struct ctl_table *table, int write,
 extern int dirty_bytes_handler(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp,
                loff_t *ppos);
+int dirtytime_interval_handler(struct ctl_table *table, int write,
+                              void __user *buffer, size_t *lenp, loff_t *ppos);
 
 struct ctl_table;
 int dirty_writeback_centisecs_handler(struct ctl_table *, int,
index 025c61c0dffbfe9ddfcc2cd6f9eb38b2af504d3f..6cc1eafb153a75c4665f375836f5592c282f9a8f 100644 (file)
@@ -453,22 +453,6 @@ static __inline__ void inet_reset_saddr(struct sock *sk)
 
 #endif
 
-static inline int sk_mc_loop(struct sock *sk)
-{
-       if (!sk)
-               return 1;
-       switch (sk->sk_family) {
-       case AF_INET:
-               return inet_sk(sk)->mc_loop;
-#if IS_ENABLED(CONFIG_IPV6)
-       case AF_INET6:
-               return inet6_sk(sk)->mc_loop;
-#endif
-       }
-       WARN_ON(1);
-       return 1;
-}
-
 bool ip_call_ra_chain(struct sk_buff *skb);
 
 /*
index 1d09b46c1e489325b95f9987327d95ca8affed08..eda131d179d971147f5b7ac254876dbf07946861 100644 (file)
@@ -174,7 +174,8 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
 
 static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
 {
-       struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
+       struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ?
+                               inet6_sk(skb->sk) : NULL;
 
        return (np && np->pmtudisc >= IPV6_PMTUDISC_PROBE) ?
               skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
index ab186b1d31fffe7cc5b4888d85aca99c2d875da4..e4079c28e6b8588da92a8826d63e07195859a33b 100644 (file)
@@ -1762,6 +1762,8 @@ struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie);
 
 struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie);
 
+bool sk_mc_loop(struct sock *sk);
+
 static inline bool sk_can_gso(const struct sock *sk)
 {
        return net_gso_ok(sk->sk_route_caps, sk->sk_gso_type);
index 0d7608dc1a345ce63f95596081e4b2752221f95d..5507eead58634f0aba8b2ad6766245346ff58117 100644 (file)
@@ -39,6 +39,7 @@
 #define NOUVEAU_GEM_DOMAIN_VRAM      (1 << 1)
 #define NOUVEAU_GEM_DOMAIN_GART      (1 << 2)
 #define NOUVEAU_GEM_DOMAIN_MAPPABLE  (1 << 3)
+#define NOUVEAU_GEM_DOMAIN_COHERENT  (1 << 4)
 
 #define NOUVEAU_GEM_TILE_COMP        0x00030000 /* nv50-only */
 #define NOUVEAU_GEM_TILE_LAYOUT_MASK 0x0000ff00
index 50d0fb41a3bf32cb2a796f3738adb10d79e3fb6c..871e73f99a4d7aa13b4cd6f5bc8969421c2a9301 100644 (file)
@@ -1034,6 +1034,10 @@ struct drm_radeon_cs {
 #define RADEON_INFO_VRAM_USAGE         0x1e
 #define RADEON_INFO_GTT_USAGE          0x1f
 #define RADEON_INFO_ACTIVE_CU_COUNT    0x20
+#define RADEON_INFO_CURRENT_GPU_TEMP   0x21
+#define RADEON_INFO_CURRENT_GPU_SCLK   0x22
+#define RADEON_INFO_CURRENT_GPU_MCLK   0x23
+#define RADEON_INFO_READ_REG           0x24
 
 struct drm_radeon_info {
        uint32_t                request;
index c15d781ecc0f306ce5fd575192f547b8e756273f..5391780c2b054ba63ec6a2a24effe66bec248af0 100644 (file)
@@ -36,7 +36,8 @@ struct drm_tegra_gem_create {
 
 struct drm_tegra_gem_mmap {
        __u32 handle;
-       __u32 offset;
+       __u32 pad;
+       __u64 offset;
 };
 
 struct drm_tegra_syncpt_read {
index b0a81307985282005ade90ee6da96e3048c405d3..2f62ab2d7bf99bd75b16eef6db74ce8aa233e8ff 100644 (file)
@@ -973,7 +973,8 @@ struct input_keymap_entry {
  */
 #define MT_TOOL_FINGER         0
 #define MT_TOOL_PEN            1
-#define MT_TOOL_MAX            1
+#define MT_TOOL_PALM           2
+#define MT_TOOL_MAX            2
 
 /*
  * Values describing the status of a force-feedback effect
index 23b40908be3061f228c118323535cc2dc2a9854d..83ea46f4be51fcf3f8922481b1cb9b5feeff2ae2 100644 (file)
 
 #define MEDIA_BUS_FMT_FIXED                    0x0001
 
-/* RGB - next is       0x100e */
+/* RGB - next is       0x1016 */
+#define MEDIA_BUS_FMT_RGB444_1X12              0x100e
 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE      0x1001
 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE      0x1002
 #define MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE      0x1003
 #define MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE      0x1004
+#define MEDIA_BUS_FMT_RGB565_1X16              0x100f
 #define MEDIA_BUS_FMT_BGR565_2X8_BE            0x1005
 #define MEDIA_BUS_FMT_BGR565_2X8_LE            0x1006
 #define MEDIA_BUS_FMT_RGB565_2X8_BE            0x1007
 #define MEDIA_BUS_FMT_RGB565_2X8_LE            0x1008
 #define MEDIA_BUS_FMT_RGB666_1X18              0x1009
+#define MEDIA_BUS_FMT_RGB666_1X24_CPADHI       0x1015
+#define MEDIA_BUS_FMT_RGB666_1X7X3_SPWG                0x1010
+#define MEDIA_BUS_FMT_BGR888_1X24              0x1013
+#define MEDIA_BUS_FMT_GBR888_1X24              0x1014
 #define MEDIA_BUS_FMT_RGB888_1X24              0x100a
 #define MEDIA_BUS_FMT_RGB888_2X12_BE           0x100b
 #define MEDIA_BUS_FMT_RGB888_2X12_LE           0x100c
+#define MEDIA_BUS_FMT_RGB888_1X7X4_SPWG                0x1011
+#define MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA       0x1012
 #define MEDIA_BUS_FMT_ARGB8888_1X32            0x100d
 
-/* YUV (including grey) - next is      0x2024 */
+/* YUV (including grey) - next is      0x2025 */
 #define MEDIA_BUS_FMT_Y8_1X8                   0x2001
 #define MEDIA_BUS_FMT_UV8_1X8                  0x2015
 #define MEDIA_BUS_FMT_UYVY8_1_5X8              0x2002
@@ -74,6 +82,7 @@
 #define MEDIA_BUS_FMT_VYUY10_1X20              0x201b
 #define MEDIA_BUS_FMT_YUYV10_1X20              0x200d
 #define MEDIA_BUS_FMT_YVYU10_1X20              0x200e
+#define MEDIA_BUS_FMT_YUV8_1X24                        0x2024
 #define MEDIA_BUS_FMT_YUV10_1X30               0x2016
 #define MEDIA_BUS_FMT_AYUV8_1X32               0x2017
 #define MEDIA_BUS_FMT_UYVY12_2X12              0x201c
index 4742f2cb42f2bd46180421efef423f101579bd03..d3bd6ffec04101138e831076789fc11cee98f2be 100644 (file)
@@ -47,7 +47,7 @@
  * exported filesystem.
  */
 #define        NFSEXP_V4ROOT           0x10000
-#define NFSEXP_NOPNFS          0x20000
+#define NFSEXP_PNFS            0x20000
 
 /* All flags that we claim to support.  (Note we don't support NOACL.) */
 #define NFSEXP_ALLFLAGS                0x3FE7F
index 73390c120cad03ec38030e68a4e5a1801d5fe668..85dedca3dcfb04e738764023b673a7ba3d47926d 100644 (file)
@@ -39,7 +39,7 @@ struct ipu_di_signal_cfg {
 
        struct videomode mode;
 
-       u32 pixel_fmt;
+       u32 bus_format;
        u32 v_to_h_sync;
 
 #define IPU_DI_CLKMODE_SYNC    (1 << 0)
index a20e4a3a8b15cb5deaaa7f6534403ccb751d4284..0530e5a4c6b1f6a84ecc16a343e9d767dd7bf8af 100644 (file)
 #define VIDISD14C_ALPHA1_B_LIMIT               0xf
 #define VIDISD14C_ALPHA1_B(_x)                 ((_x) << 0)
 
+#define VIDW_ALPHA                             0x021c
+#define VIDW_ALPHA_R(_x)                       ((_x) << 16)
+#define VIDW_ALPHA_G(_x)                       ((_x) << 8)
+#define VIDW_ALPHA_B(_x)                       ((_x) << 0)
+
 /* Video buffer addresses */
 #define VIDW_BUF_START(_buff)                  (0xA0 + ((_buff) * 8))
 #define VIDW_BUF_START1(_buff)                 (0xA4 + ((_buff) * 8))
 #define BLENDCON_NEW_8BIT_ALPHA_VALUE          (1 << 0)
 #define BLENDCON_NEW_4BIT_ALPHA_VALUE          (0 << 0)
 
+/* Display port clock control */
+#define DP_MIE_CLKCON                          0x27c
+#define DP_MIE_CLK_DISABLE                     0x0
+#define DP_MIE_CLK_DP_ENABLE                   0x2
+#define DP_MIE_CLK_MIE_ENABLE                  0x3
+
 /* Notes on per-window bpp settings
  *
  * Value       Win0     Win1     Win2     Win3     Win 4
index 88ea2d6e00314059b96adb0505ffc5f9c98fcf73..ce410bb9f2e103e0fcfda7d7b844948a0a28fbce 100644 (file)
@@ -1227,6 +1227,14 @@ static struct ctl_table vm_table[] = {
                .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
        },
+       {
+               .procname       = "dirtytime_expire_seconds",
+               .data           = &dirtytime_expire_interval,
+               .maxlen         = sizeof(dirty_expire_interval),
+               .mode           = 0644,
+               .proc_handler   = dirtytime_interval_handler,
+               .extra1         = &zero,
+       },
        {
                .procname       = "nr_pdflush_threads",
                .mode           = 0444 /* read-only */,
index e97dbd51e7569f6a7ba273227752f2cdbcaebb49..03d7fcb420b5d60c564ad10935011ed8a6556b69 100644 (file)
--- a/lib/lcm.c
+++ b/lib/lcm.c
@@ -12,3 +12,14 @@ unsigned long lcm(unsigned long a, unsigned long b)
                return 0;
 }
 EXPORT_SYMBOL_GPL(lcm);
+
+unsigned long lcm_not_zero(unsigned long a, unsigned long b)
+{
+       unsigned long l = lcm(a, b);
+
+       if (l)
+               return l;
+
+       return (b ? : a);
+}
+EXPORT_SYMBOL_GPL(lcm_not_zero);
index 76a1b59523ab05907403f4f9bd5dc547fca1bcab..f5907d23272d48562c69b911e5a0a619e3f4c180 100644 (file)
@@ -279,6 +279,8 @@ int nla_memcpy(void *dest, const struct nlattr *src, int count)
        int minlen = min_t(int, count, nla_len(src));
 
        memcpy(dest, nla_data(src), minlen);
+       if (count > minlen)
+               memset(dest + minlen, 0, count - minlen);
 
        return minlen;
 }
index 962ee9d719641291853715f366717bf1626e115c..45109b70664e8abb1b7957aabd619c4e0d711db4 100644 (file)
@@ -2848,7 +2848,9 @@ static void skb_update_prio(struct sk_buff *skb)
 #define skb_update_prio(skb)
 #endif
 
-static DEFINE_PER_CPU(int, xmit_recursion);
+DEFINE_PER_CPU(int, xmit_recursion);
+EXPORT_SYMBOL(xmit_recursion);
+
 #define RECURSION_LIMIT 10
 
 /**
index 44706e81b2e03df3e9d39c1cd76879a4ede48d1e..e4fdc9dfb2c73fb371280464484ebcae87218be6 100644 (file)
@@ -175,9 +175,9 @@ void fib_rules_unregister(struct fib_rules_ops *ops)
 
        spin_lock(&net->rules_mod_lock);
        list_del_rcu(&ops->list);
-       fib_rules_cleanup_ops(ops);
        spin_unlock(&net->rules_mod_lock);
 
+       fib_rules_cleanup_ops(ops);
        call_rcu(&ops->rcu, fib_rules_put_rcu);
 }
 EXPORT_SYMBOL_GPL(fib_rules_unregister);
index cb5290b8c428c5c348b25d842ab9cf3797b70eba..70d3450588b2c73cbb4a3027f7f92e0c285b90d7 100644 (file)
@@ -198,8 +198,10 @@ static int __peernet2id(struct net *net, struct net *peer, bool alloc)
  */
 int peernet2id(struct net *net, struct net *peer)
 {
-       int id = __peernet2id(net, peer, true);
+       bool alloc = atomic_read(&peer->count) == 0 ? false : true;
+       int id;
 
+       id = __peernet2id(net, peer, alloc);
        return id >= 0 ? id : NETNSA_NSID_NOT_ASSIGNED;
 }
 EXPORT_SYMBOL(peernet2id);
index ee0608bb3bc087212d12bac729677bf454053560..7ebed55b5f7d1b2d1faacea1a49e7f9e947f43d1 100644 (file)
@@ -1932,10 +1932,10 @@ static int rtnl_group_changelink(const struct sk_buff *skb,
                struct ifinfomsg *ifm,
                struct nlattr **tb)
 {
-       struct net_device *dev;
+       struct net_device *dev, *aux;
        int err;
 
-       for_each_netdev(net, dev) {
+       for_each_netdev_safe(net, dev, aux) {
                if (dev->group == group) {
                        err = do_setlink(skb, dev, ifm, tb, NULL, 0);
                        if (err < 0)
index 78e89eb7eb705624d3ff63324f5002ae10b51145..71e3e5f1eaa04816b8bdd1d34b4fd575f19793b9 100644 (file)
@@ -653,6 +653,25 @@ static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool)
                sock_reset_flag(sk, bit);
 }
 
+bool sk_mc_loop(struct sock *sk)
+{
+       if (dev_recursion_level())
+               return false;
+       if (!sk)
+               return true;
+       switch (sk->sk_family) {
+       case AF_INET:
+               return inet_sk(sk)->mc_loop;
+#if IS_ENABLED(CONFIG_IPV6)
+       case AF_INET6:
+               return inet6_sk(sk)->mc_loop;
+#endif
+       }
+       WARN_ON(1);
+       return true;
+}
+EXPORT_SYMBOL(sk_mc_loop);
+
 /*
  *     This is meant for all protocols to use and covers goings on
  *     at the socket level. Everything here is generic.
index faf7cc3483fe0822c26be6b915061ee8fdd8be9a..9d66a0f72f906733878de68e7f2e6bd80932c1b9 100644 (file)
@@ -248,7 +248,9 @@ void __init dn_fib_rules_init(void)
 
 void __exit dn_fib_rules_cleanup(void)
 {
+       rtnl_lock();
        fib_rules_unregister(dn_fib_rules_ops);
+       rtnl_unlock();
        rcu_barrier();
 }
 
index 2173402d87e0f56f255d0b378f06fc51aa2d3fed..4dea2e0681d16409016ae09616127b22bbab3a1e 100644 (file)
@@ -501,12 +501,10 @@ static struct net_device *dev_to_net_device(struct device *dev)
 #ifdef CONFIG_OF
 static int dsa_of_setup_routing_table(struct dsa_platform_data *pd,
                                        struct dsa_chip_data *cd,
-                                       int chip_index,
+                                       int chip_index, int port_index,
                                        struct device_node *link)
 {
-       int ret;
        const __be32 *reg;
-       int link_port_addr;
        int link_sw_addr;
        struct device_node *parent_sw;
        int len;
@@ -519,6 +517,10 @@ static int dsa_of_setup_routing_table(struct dsa_platform_data *pd,
        if (!reg || (len != sizeof(*reg) * 2))
                return -EINVAL;
 
+       /*
+        * Get the destination switch number from the second field of its 'reg'
+        * property, i.e. for "reg = <0x19 1>" sw_addr is '1'.
+        */
        link_sw_addr = be32_to_cpup(reg + 1);
 
        if (link_sw_addr >= pd->nr_chips)
@@ -535,20 +537,9 @@ static int dsa_of_setup_routing_table(struct dsa_platform_data *pd,
                memset(cd->rtable, -1, pd->nr_chips * sizeof(s8));
        }
 
-       reg = of_get_property(link, "reg", NULL);
-       if (!reg) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       link_port_addr = be32_to_cpup(reg);
-
-       cd->rtable[link_sw_addr] = link_port_addr;
+       cd->rtable[link_sw_addr] = port_index;
 
        return 0;
-out:
-       kfree(cd->rtable);
-       return ret;
 }
 
 static void dsa_of_free_platform_data(struct dsa_platform_data *pd)
@@ -658,7 +649,7 @@ static int dsa_of_probe(struct platform_device *pdev)
                        if (!strcmp(port_name, "dsa") && link &&
                                        pd->nr_chips > 1) {
                                ret = dsa_of_setup_routing_table(pd, cd,
-                                               chip_index, link);
+                                               chip_index, port_index, link);
                                if (ret)
                                        goto out_free_chip;
                        }
index 57be71dd6a9e0163dceefd564bf71036c12dc9ba..23b9b3e86f4cd78987790f3456470318e3b82ece 100644 (file)
@@ -1111,11 +1111,10 @@ static void ip_fib_net_exit(struct net *net)
 {
        unsigned int i;
 
+       rtnl_lock();
 #ifdef CONFIG_IP_MULTIPLE_TABLES
        fib4_rules_exit(net);
 #endif
-
-       rtnl_lock();
        for (i = 0; i < FIB_TABLE_HASHSZ; i++) {
                struct fib_table *tb;
                struct hlist_head *head;
index 9d78427652d23e33a46ab7ce2d4b6dbac1660781..fe54eba6d00d3462c287b095370e3a938e73b178 100644 (file)
@@ -268,7 +268,7 @@ static int __net_init ipmr_rules_init(struct net *net)
        return 0;
 
 err2:
-       kfree(mrt);
+       ipmr_free_table(mrt);
 err1:
        fib_rules_unregister(ops);
        return err;
@@ -278,11 +278,13 @@ static void __net_exit ipmr_rules_exit(struct net *net)
 {
        struct mr_table *mrt, *next;
 
+       rtnl_lock();
        list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) {
                list_del(&mrt->list);
                ipmr_free_table(mrt);
        }
        fib_rules_unregister(net->ipv4.mr_rules_ops);
+       rtnl_unlock();
 }
 #else
 #define ipmr_for_each_table(mrt, net) \
@@ -308,7 +310,10 @@ static int __net_init ipmr_rules_init(struct net *net)
 
 static void __net_exit ipmr_rules_exit(struct net *net)
 {
+       rtnl_lock();
        ipmr_free_table(net->ipv4.mrt);
+       net->ipv4.mrt = NULL;
+       rtnl_unlock();
 }
 #endif
 
index fb4cf8b8e121acd4bffcf2fdfbd7e03c76bad7cc..f501ac0483665aeb1100e2f2776d3f38610e9b30 100644 (file)
@@ -3105,10 +3105,11 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
                        if (!first_ackt.v64)
                                first_ackt = last_ackt;
 
-                       if (!(sacked & TCPCB_SACKED_ACKED))
+                       if (!(sacked & TCPCB_SACKED_ACKED)) {
                                reord = min(pkts_acked, reord);
-                       if (!after(scb->end_seq, tp->high_seq))
-                               flag |= FLAG_ORIG_SACK_ACKED;
+                               if (!after(scb->end_seq, tp->high_seq))
+                                       flag |= FLAG_ORIG_SACK_ACKED;
+                       }
                }
 
                if (sacked & TCPCB_SACKED_ACKED)
index 5a2dfed4783b6ed0185dccded960972b4d6e13b0..f1756ee022078d12e74be5d245fc1a6a0c1c4a34 100644 (file)
@@ -1518,7 +1518,7 @@ void tcp_v4_early_demux(struct sk_buff *skb)
                skb->sk = sk;
                skb->destructor = sock_edemux;
                if (sk->sk_state != TCP_TIME_WAIT) {
-                       struct dst_entry *dst = sk->sk_rx_dst;
+                       struct dst_entry *dst = READ_ONCE(sk->sk_rx_dst);
 
                        if (dst)
                                dst = dst_check(dst, 0);
index 27ca79682efbf681a0ab6073f50f8fa73214028e..70bc6abc0639cf88d0b23b295c20d941b456d98b 100644 (file)
@@ -322,7 +322,9 @@ out_fib6_rules_ops:
 
 static void __net_exit fib6_rules_net_exit(struct net *net)
 {
+       rtnl_lock();
        fib_rules_unregister(net->ipv6.fib6_rules_ops);
+       rtnl_unlock();
 }
 
 static struct pernet_operations fib6_rules_net_ops = {
index 7e80b61b51ff474db6c188218b70f12709209256..36cf0ab685a00d57fbdc6787ba77116dae638f21 100644 (file)
@@ -542,7 +542,8 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 {
        struct sk_buff *frag;
        struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
-       struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
+       struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ?
+                               inet6_sk(skb->sk) : NULL;
        struct ipv6hdr *tmp_hdr;
        struct frag_hdr *fh;
        unsigned int mtu, hlen, left, len;
index 34b682617f504359cecff4447c6015f90623e949..312e0ff47339be3a3ffa8981c9e1b1cb7f5a551b 100644 (file)
@@ -252,7 +252,7 @@ static int __net_init ip6mr_rules_init(struct net *net)
        return 0;
 
 err2:
-       kfree(mrt);
+       ip6mr_free_table(mrt);
 err1:
        fib_rules_unregister(ops);
        return err;
@@ -267,8 +267,8 @@ static void __net_exit ip6mr_rules_exit(struct net *net)
                list_del(&mrt->list);
                ip6mr_free_table(mrt);
        }
-       rtnl_unlock();
        fib_rules_unregister(net->ipv6.mr6_rules_ops);
+       rtnl_unlock();
 }
 #else
 #define ip6mr_for_each_table(mrt, net) \
@@ -336,7 +336,7 @@ static struct mr6_table *ip6mr_new_table(struct net *net, u32 id)
 
 static void ip6mr_free_table(struct mr6_table *mrt)
 {
-       del_timer(&mrt->ipmr_expire_timer);
+       del_timer_sync(&mrt->ipmr_expire_timer);
        mroute_clean_tables(mrt);
        kfree(mrt);
 }
index 471ed24aabaec4b1d8736438696ca3490d4e0f58..14ecdaf06bf7497dc71199fc5638b49592a24655 100644 (file)
@@ -1218,7 +1218,14 @@ static void ndisc_router_discovery(struct sk_buff *skb)
        if (rt)
                rt6_set_expires(rt, jiffies + (HZ * lifetime));
        if (ra_msg->icmph.icmp6_hop_limit) {
-               in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
+               /* Only set hop_limit on the interface if it is higher than
+                * the current hop_limit.
+                */
+               if (in6_dev->cnf.hop_limit < ra_msg->icmph.icmp6_hop_limit) {
+                       in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
+               } else {
+                       ND_PRINTK(2, warn, "RA: Got route advertisement with lower hop_limit than current\n");
+               }
                if (rt)
                        dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
                                       ra_msg->icmph.icmp6_hop_limit);
index 5d46832c6f72b89a278a3326918a3c8bff9afed4..1f5e62229aaa8b4d5822f82c3af3a6c8b1382ba6 100644 (file)
@@ -1411,6 +1411,15 @@ static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr,
        TCP_SKB_CB(skb)->sacked = 0;
 }
 
+static void tcp_v6_restore_cb(struct sk_buff *skb)
+{
+       /* We need to move header back to the beginning if xfrm6_policy_check()
+        * and tcp_v6_fill_cb() are going to be called again.
+        */
+       memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
+               sizeof(struct inet6_skb_parm));
+}
+
 static int tcp_v6_rcv(struct sk_buff *skb)
 {
        const struct tcphdr *th;
@@ -1543,6 +1552,7 @@ do_time_wait:
                        inet_twsk_deschedule(tw, &tcp_death_row);
                        inet_twsk_put(tw);
                        sk = sk2;
+                       tcp_v6_restore_cb(skb);
                        goto process;
                }
                /* Fall through to ACK */
@@ -1551,6 +1561,7 @@ do_time_wait:
                tcp_v6_timewait_ack(sk, skb);
                break;
        case TCP_TW_RST:
+               tcp_v6_restore_cb(skb);
                goto no_tcp_socket;
        case TCP_TW_SUCCESS:
                ;
@@ -1585,7 +1596,7 @@ static void tcp_v6_early_demux(struct sk_buff *skb)
                skb->sk = sk;
                skb->destructor = sock_edemux;
                if (sk->sk_state != TCP_TIME_WAIT) {
-                       struct dst_entry *dst = sk->sk_rx_dst;
+                       struct dst_entry *dst = READ_ONCE(sk->sk_rx_dst);
 
                        if (dst)
                                dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie);
index 2e9953b2db8402dd71c88691f263db00f2cba3e2..53d931172088b15b2890c42dd649308771b6e7d3 100644 (file)
@@ -1114,10 +1114,8 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                        noblock, &err);
        else
                skb = sock_alloc_send_skb(sk, len, noblock, &err);
-       if (!skb) {
-               err = -ENOMEM;
+       if (!skb)
                goto out;
-       }
        if (iucv->transport == AF_IUCV_TRANS_HIPER)
                skb_reserve(skb, sizeof(struct af_iucv_trans_hdr) + ETH_HLEN);
        if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
index 895348e44c7d22c9e6d4828195e7099a74154531..a29a504492af6f2c38607f2c15e123a297d565cd 100644 (file)
@@ -1871,6 +1871,7 @@ static int __init l2tp_init(void)
        l2tp_wq = alloc_workqueue("l2tp", WQ_UNBOUND, 0);
        if (!l2tp_wq) {
                pr_err("alloc_workqueue failed\n");
+               unregister_pernet_device(&l2tp_net_ops);
                rc = -ENOMEM;
                goto out;
        }
index a48bad468880aa60c80b45a1cc97bef616845ffa..7702978a4c999dfd10d9b49792b8b25899e23966 100644 (file)
@@ -49,8 +49,6 @@ static void ieee80211_free_tid_rx(struct rcu_head *h)
                container_of(h, struct tid_ampdu_rx, rcu_head);
        int i;
 
-       del_timer_sync(&tid_rx->reorder_timer);
-
        for (i = 0; i < tid_rx->buf_size; i++)
                __skb_queue_purge(&tid_rx->reorder_buf[i]);
        kfree(tid_rx->reorder_buf);
@@ -93,6 +91,12 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
 
        del_timer_sync(&tid_rx->session_timer);
 
+       /* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */
+       spin_lock_bh(&tid_rx->reorder_lock);
+       tid_rx->removed = true;
+       spin_unlock_bh(&tid_rx->reorder_lock);
+       del_timer_sync(&tid_rx->reorder_timer);
+
        call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx);
 }
 
index 944bdc04e913d2f599b6c5845ee2549abba20a1c..1eb730bf875272831d44ac62c6e5a18e0a1de977 100644 (file)
@@ -873,9 +873,10 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
 
  set_release_timer:
 
-               mod_timer(&tid_agg_rx->reorder_timer,
-                         tid_agg_rx->reorder_time[j] + 1 +
-                         HT_RX_REORDER_BUF_TIMEOUT);
+               if (!tid_agg_rx->removed)
+                       mod_timer(&tid_agg_rx->reorder_timer,
+                                 tid_agg_rx->reorder_time[j] + 1 +
+                                 HT_RX_REORDER_BUF_TIMEOUT);
        } else {
                del_timer(&tid_agg_rx->reorder_timer);
        }
index 925e68fe64c755766c2ecc30d047455f62c11362..fb0fc1302a588480cae6649e2e671ffa719de36b 100644 (file)
@@ -175,6 +175,7 @@ struct tid_ampdu_tx {
  * @reorder_lock: serializes access to reorder buffer, see below.
  * @auto_seq: used for offloaded BA sessions to automatically pick head_seq_and
  *     and ssn.
+ * @removed: this session is removed (but might have been found due to RCU)
  *
  * This structure's lifetime is managed by RCU, assignments to
  * the array holding it must hold the aggregation mutex.
@@ -199,6 +200,7 @@ struct tid_ampdu_rx {
        u16 timeout;
        u8 dialog_token;
        bool auto_seq;
+       bool removed;
 };
 
 /**
index ec2954ffc690c612eb1b04b018134ba0f52ba5c8..067a3fff1d2cb0c629c1dc2d75d0353b9269ba71 100644 (file)
@@ -274,10 +274,8 @@ void ovs_vport_del(struct vport *vport)
        ASSERT_OVSL();
 
        hlist_del_rcu(&vport->hash_node);
-
-       vport->ops->destroy(vport);
-
        module_put(vport->ops->owner);
+       vport->ops->destroy(vport);
 }
 
 /**
index 612aa73bbc60c990a320054e4bd7d2846575428e..e6ce1517367f884608640b2532080ab6566b9379 100644 (file)
@@ -303,9 +303,7 @@ static int rpc_client_register(struct rpc_clnt *clnt,
        struct super_block *pipefs_sb;
        int err;
 
-       err = rpc_clnt_debugfs_register(clnt);
-       if (err)
-               return err;
+       rpc_clnt_debugfs_register(clnt);
 
        pipefs_sb = rpc_get_sb_net(net);
        if (pipefs_sb) {
index e811f390f9f67ceb2e897ee8da79189417eacc75..82962f7e6e888f619ad79754f038732d5d5b6333 100644 (file)
@@ -129,48 +129,52 @@ static const struct file_operations tasks_fops = {
        .release        = tasks_release,
 };
 
-int
+void
 rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
 {
-       int len, err;
+       int len;
        char name[24]; /* enough for "../../rpc_xprt/ + 8 hex digits + NULL */
+       struct rpc_xprt *xprt;
 
        /* Already registered? */
-       if (clnt->cl_debugfs)
-               return 0;
+       if (clnt->cl_debugfs || !rpc_clnt_dir)
+               return;
 
        len = snprintf(name, sizeof(name), "%x", clnt->cl_clid);
        if (len >= sizeof(name))
-               return -EINVAL;
+               return;
 
        /* make the per-client dir */
        clnt->cl_debugfs = debugfs_create_dir(name, rpc_clnt_dir);
        if (!clnt->cl_debugfs)
-               return -ENOMEM;
+               return;
 
        /* make tasks file */
-       err = -ENOMEM;
        if (!debugfs_create_file("tasks", S_IFREG | S_IRUSR, clnt->cl_debugfs,
                                 clnt, &tasks_fops))
                goto out_err;
 
-       err = -EINVAL;
        rcu_read_lock();
+       xprt = rcu_dereference(clnt->cl_xprt);
+       /* no "debugfs" dentry? Don't bother with the symlink. */
+       if (!xprt->debugfs) {
+               rcu_read_unlock();
+               return;
+       }
        len = snprintf(name, sizeof(name), "../../rpc_xprt/%s",
-                       rcu_dereference(clnt->cl_xprt)->debugfs->d_name.name);
+                       xprt->debugfs->d_name.name);
        rcu_read_unlock();
+
        if (len >= sizeof(name))
                goto out_err;
 
-       err = -ENOMEM;
        if (!debugfs_create_symlink("xprt", clnt->cl_debugfs, name))
                goto out_err;
 
-       return 0;
+       return;
 out_err:
        debugfs_remove_recursive(clnt->cl_debugfs);
        clnt->cl_debugfs = NULL;
-       return err;
 }
 
 void
@@ -226,33 +230,33 @@ static const struct file_operations xprt_info_fops = {
        .release        = xprt_info_release,
 };
 
-int
+void
 rpc_xprt_debugfs_register(struct rpc_xprt *xprt)
 {
        int len, id;
        static atomic_t cur_id;
        char            name[9]; /* 8 hex digits + NULL term */
 
+       if (!rpc_xprt_dir)
+               return;
+
        id = (unsigned int)atomic_inc_return(&cur_id);
 
        len = snprintf(name, sizeof(name), "%x", id);
        if (len >= sizeof(name))
-               return -EINVAL;
+               return;
 
        /* make the per-client dir */
        xprt->debugfs = debugfs_create_dir(name, rpc_xprt_dir);
        if (!xprt->debugfs)
-               return -ENOMEM;
+               return;
 
        /* make tasks file */
        if (!debugfs_create_file("info", S_IFREG | S_IRUSR, xprt->debugfs,
                                 xprt, &xprt_info_fops)) {
                debugfs_remove_recursive(xprt->debugfs);
                xprt->debugfs = NULL;
-               return -ENOMEM;
        }
-
-       return 0;
 }
 
 void
@@ -266,14 +270,17 @@ void __exit
 sunrpc_debugfs_exit(void)
 {
        debugfs_remove_recursive(topdir);
+       topdir = NULL;
+       rpc_clnt_dir = NULL;
+       rpc_xprt_dir = NULL;
 }
 
-int __init
+void __init
 sunrpc_debugfs_init(void)
 {
        topdir = debugfs_create_dir("sunrpc", NULL);
        if (!topdir)
-               goto out;
+               return;
 
        rpc_clnt_dir = debugfs_create_dir("rpc_clnt", topdir);
        if (!rpc_clnt_dir)
@@ -283,10 +290,9 @@ sunrpc_debugfs_init(void)
        if (!rpc_xprt_dir)
                goto out_remove;
 
-       return 0;
+       return;
 out_remove:
        debugfs_remove_recursive(topdir);
        topdir = NULL;
-out:
-       return -ENOMEM;
+       rpc_clnt_dir = NULL;
 }
index e37fbed879568da535aa540656e7b7ace508e2cb..ee5d3d253102bf5d81a39f953248a6a6ca7a38d6 100644 (file)
@@ -98,10 +98,7 @@ init_sunrpc(void)
        if (err)
                goto out4;
 
-       err = sunrpc_debugfs_init();
-       if (err)
-               goto out5;
-
+       sunrpc_debugfs_init();
 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
        rpc_register_sysctl();
 #endif
@@ -109,8 +106,6 @@ init_sunrpc(void)
        init_socket_xprt();     /* clnt sock transport */
        return 0;
 
-out5:
-       unregister_rpc_pipefs();
 out4:
        unregister_pernet_subsys(&sunrpc_net_ops);
 out3:
index e3015aede0d9443d99eba6b820aed104ab7515a6..9949722d99cebf6afa15953d8a9ac6a5c0bc2824 100644 (file)
@@ -1331,7 +1331,6 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net)
  */
 struct rpc_xprt *xprt_create_transport(struct xprt_create *args)
 {
-       int err;
        struct rpc_xprt *xprt;
        struct xprt_class *t;
 
@@ -1372,11 +1371,7 @@ found:
                return ERR_PTR(-ENOMEM);
        }
 
-       err = rpc_xprt_debugfs_register(xprt);
-       if (err) {
-               xprt_destroy(xprt);
-               return ERR_PTR(err);
-       }
+       rpc_xprt_debugfs_register(xprt);
 
        dprintk("RPC:       created transport %p with %u slots\n", xprt,
                        xprt->max_reqs);
index 935205e6bcfe6da614fcc6c67e77754dc3a484fa..be1c9fa60b09dc713155c94e7bf6bcc6366fc7aa 100644 (file)
@@ -152,11 +152,11 @@ out_netlink:
 static void __exit tipc_exit(void)
 {
        tipc_bearer_cleanup();
+       unregister_pernet_subsys(&tipc_net_ops);
        tipc_netlink_stop();
        tipc_netlink_compat_stop();
        tipc_socket_stop();
        tipc_unregister_sysctl();
-       unregister_pernet_subsys(&tipc_net_ops);
 
        pr_info("Deactivated\n");
 }